Merge "Merge "Merge "DO NOT MERGE: This test case tries to decode a corrupt image file using BitmapFactory.decodeStream which causes Process crash on an unpatched device, thus failing the test." into lollipop-cts-dev am: b0d4b6797d -s ours" into lollipop-mr1-cts-dev am: 04ec7def27 -s ours" into marshmallow-cts-dev am: ea883af7fe -s ours am: 69b840344d am: f758bed62a am: 136d9d0c0e am: 2655db6a27 -s ours am: d449ee6262 am: 580a6886af
am: 0a5589fd07 -s ours
* commit '0a5589fd072164947f57b1641105d937a943753f':
Change-Id: I8461b0f97cad94784a130fd53068955b4d0221fe
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index e79659b..1b63e53 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -152,7 +152,7 @@
helpBuilder.append(" help: show this message.\n");
helpBuilder.append(" help all: show the complete tradefed help.\n");
helpBuilder.append(" version: show the version.\n");
- helpBuilder.append(" exit: gracefully exit the compatibiltiy console, waiting until all ");
+ helpBuilder.append(" exit: gracefully exit the compatibility console, waiting until all ");
helpBuilder.append("invocations have completed.\n");
helpBuilder.append("Run:\n");
final String runPrompt = " run <plan> ";
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index eb4a091..19fd3bd 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -26,7 +26,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner android-support-test
LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index 85c74f9..7003012 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -27,7 +27,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner compatibility-device-util \
- ub-uiautomator
+ ub-uiautomator android-support-test
LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/numberblocking/app/Android.mk b/hostsidetests/numberblocking/app/Android.mk
index 492a2ec..5755f84 100644
--- a/hostsidetests/numberblocking/app/Android.mk
+++ b/hostsidetests/numberblocking/app/Android.mk
@@ -27,7 +27,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index 775e679..6ce0148 100644
--- a/tests/app/Android.mk
+++ b/tests/app/Android.mk
@@ -23,7 +23,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common voip-common org.apache.http.legacy
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ctstestserver mockito-target android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 10a6792..a467088 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -196,6 +196,8 @@
</intent-filter>
</activity>
+ <activity android:name="android.app.stubs.FragmentResultActivity" android:label="FragmentResultActivity" />
+
<activity android:name="android.app.stubs.ChildTabActivity" android:label="ChildTabActivity" />
<activity android:name="android.app.stubs.LauncherActivityStub"
diff --git a/tests/app/app/src/android/app/stubs/FragmentResultActivity.java b/tests/app/app/src/android/app/stubs/FragmentResultActivity.java
new file mode 100644
index 0000000..364d093
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/FragmentResultActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.stubs;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * A simple Activity used to return a result.
+ */
+public class FragmentResultActivity extends Activity {
+ public static final String EXTRA_RESULT_CODE = "result";
+ public static final String EXTRA_RESULT_CONTENT = "result_content";
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ int resultCode = getIntent().getIntExtra(EXTRA_RESULT_CODE, Activity.RESULT_OK);
+ String result = getIntent().getStringExtra(EXTRA_RESULT_CONTENT);
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_RESULT_CONTENT, result);
+ setResult(resultCode, intent);
+ finish();
+ }
+}
diff --git a/tests/app/app/src/android/app/stubs/FragmentTestActivity.java b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
index 65ba911..9ca08b9 100644
--- a/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
+++ b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
@@ -19,6 +19,7 @@
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.transition.Transition;
import android.transition.Transition.TransitionListener;
diff --git a/tests/app/src/android/app/cts/FragmentReceiveResultTest.java b/tests/app/src/android/app/cts/FragmentReceiveResultTest.java
new file mode 100644
index 0000000..7535cc6
--- /dev/null
+++ b/tests/app/src/android/app/cts/FragmentReceiveResultTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.cts;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.Instrumentation;
+import android.app.PendingIntent;
+import android.app.stubs.FragmentResultActivity;
+import android.app.stubs.FragmentTestActivity;
+import android.app.stubs.R;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests Fragment's startActivityForResult and startIntentSenderForResult.
+ */
+public class FragmentReceiveResultTest extends
+ ActivityInstrumentationTestCase2<FragmentTestActivity> {
+
+ private FragmentTestActivity mActivity;
+ private TestFragment mFragment;
+
+ public FragmentReceiveResultTest() {
+ super(FragmentTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mFragment = attachTestFragment();
+ }
+
+ @SmallTest
+ public void testStartActivityForResultOk() {
+ startActivityForResult(10, Activity.RESULT_OK, "content 10");
+
+ assertTrue("Fragment should receive result", mFragment.mHasResult);
+ assertEquals(10, mFragment.mRequestCode);
+ assertEquals(Activity.RESULT_OK, mFragment.mResultCode);
+ assertEquals("content 10", mFragment.mResultContent);
+ }
+
+ @SmallTest
+ public void testStartActivityForResultCanceled() {
+ startActivityForResult(20, Activity.RESULT_CANCELED, "content 20");
+
+ assertTrue("Fragment should receive result", mFragment.mHasResult);
+ assertEquals(20, mFragment.mRequestCode);
+ assertEquals(Activity.RESULT_CANCELED, mFragment.mResultCode);
+ assertEquals("content 20", mFragment.mResultContent);
+ }
+
+ @SmallTest
+ public void testStartIntentSenderForResultOk() {
+ startIntentSenderForResult(30, Activity.RESULT_OK, "content 30");
+
+ assertTrue("Fragment should receive result", mFragment.mHasResult);
+ assertEquals(30, mFragment.mRequestCode);
+ assertEquals(Activity.RESULT_OK, mFragment.mResultCode);
+ assertEquals("content 30", mFragment.mResultContent);
+ }
+
+ @SmallTest
+ public void testStartIntentSenderForResultCanceled() {
+ startIntentSenderForResult(40, Activity.RESULT_CANCELED, "content 40");
+
+ assertTrue("Fragment should receive result", mFragment.mHasResult);
+ assertEquals(40, mFragment.mRequestCode);
+ assertEquals(Activity.RESULT_CANCELED, mFragment.mResultCode);
+ assertEquals("content 40", mFragment.mResultContent);
+ }
+
+ private TestFragment attachTestFragment() {
+ final TestFragment fragment = new TestFragment();
+ getInstrumentation().waitForIdleSync();
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getFragmentManager().beginTransaction()
+ .add(R.id.content, fragment)
+ .addToBackStack(null)
+ .commitAllowingStateLoss();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ return fragment;
+ }
+
+ private void startActivityForResult(final int requestCode, final int resultCode,
+ final String content) {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ Intent intent = new Intent(mActivity, FragmentResultActivity.class);
+ intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CODE, resultCode);
+ intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT, content);
+
+ mFragment.startActivityForResult(intent, requestCode);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private void startIntentSenderForResult(final int requestCode, final int resultCode,
+ final String content) {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ Intent intent = new Intent(mActivity, FragmentResultActivity.class);
+ intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CODE, resultCode);
+ intent.putExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT, content);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(mActivity,
+ requestCode, intent, 0);
+
+ try {
+ mFragment.startIntentSenderForResult(pendingIntent.getIntentSender(),
+ requestCode, null, 0, 0, 0, null);
+ } catch (IntentSender.SendIntentException e) {
+ fail("IntentSender failed");
+ }
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private final class TestFragment extends Fragment {
+ boolean mHasResult = false;
+ int mRequestCode = -1;
+ int mResultCode = 100;
+ String mResultContent;
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mHasResult = true;
+ mRequestCode = requestCode;
+ mResultCode = resultCode;
+ mResultContent = data.getStringExtra(FragmentResultActivity.EXTRA_RESULT_CONTENT);
+ }
+ }
+
+}
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index db687bf..4a3620e 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -345,7 +345,7 @@
class StaticInfo {
public:
- StaticInfo(ACameraMetadata* chars) : mChars(chars) {}
+ explicit StaticInfo(ACameraMetadata* chars) : mChars(chars) {}
bool isColorOutputSupported() {
return isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
diff --git a/tests/tests/app.usage/Android.mk b/tests/tests/app.usage/Android.mk
index 4cc3606..0303dbd 100644
--- a/tests/tests/app.usage/Android.mk
+++ b/tests/tests/app.usage/Android.mk
@@ -26,7 +26,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index 08201a6..cf76aa0b 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -26,7 +26,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index be6a759..e192a0c 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -107,4 +107,27 @@
}
}
+ public void testGetIccAuthentication() {
+ // EAP-SIM rand is 16 bytes.
+ String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM=";
+ String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ=";
+ if (!hasCellular) return;
+ try {
+ assertNull("getIccAuthentication should return null for empty data.",
+ mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA, ""));
+ String response = mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge);
+ assertTrue("Response to EAP-SIM Challenge must not be Null.", response != null);
+ // response is base64 encoded. After decoding, the value should be:
+ // 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes)
+ byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
+ assertTrue("Result length must be 14 bytes.", 14 == result.length);
+ String response2 = mTelephonyManager.getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_SIM, base64Challenge2);
+ assertTrue("Two responses must be different.", !response.equals(response2));
+ } catch (SecurityException e) {
+ failMessage();
+ }
+ }
}
diff --git a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
index 8b99003..d0aedec 100644
--- a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -25,6 +25,7 @@
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.microedition.khronos.egl.EGL10;
@@ -61,20 +62,16 @@
int detectedMajorVersion = getDetectedMajorVersion();
int reportedVersion = getVersionFromActivityManager(mActivity);
- assertEquals("Detected OpenGL ES major version " + detectedMajorVersion
- + " but Activity Manager is reporting " + getMajorVersion(reportedVersion)
- + " (Check ro.opengles.version)",
- detectedMajorVersion, getMajorVersion(reportedVersion));
assertEquals("Reported OpenGL ES version from ActivityManager differs from PackageManager",
reportedVersion, getVersionFromPackageManager(mActivity));
- assertGlVersionString(1);
+ assertGlVersionString(1, 1);
if (detectedMajorVersion == 2) {
restartActivityWithClientVersion(2);
- assertGlVersionString(2);
+ assertGlVersionString(2, getMinorVersion(reportedVersion));
} else if (detectedMajorVersion == 3) {
restartActivityWithClientVersion(3);
- assertGlVersionString(3);
+ assertGlVersionString(3, getMinorVersion(reportedVersion));
}
}
@@ -123,14 +120,11 @@
restartActivityWithClientVersion(3);
String extensions = mActivity.getExtensionsString();
- if (!hasExtension(extensions, "ANDROID_extension_pack_es31a")) {
- assertFalse("FEATURE_OPENGLES_EXTENSION_PACK is available but ANDROID_extension_pack_es31a isn't in the extension list",
- hasAepFeature);
- return;
- }
-
- assertTrue("ANDROID_extension_pack_es31a is present, but support is incomplete",
- mActivity.getAepEs31Support());
+ boolean hasAepExtension = hasExtension(extensions, "GL_ANDROID_extension_pack_es31a");
+ assertEquals("System feature FEATURE_OPENGLES_EXTENSION_PACK is "
+ + (hasAepFeature ? "" : "not ") + "available, but extension GL_ANDROID_extension_pack_es31a is "
+ + (hasAepExtension ? "" : "not ") + "in the OpenGL ES extension list.",
+ hasAepFeature, hasAepExtension);
}
public void testOpenGlEsVersionForVrHighPerformance() throws InterruptedException {
@@ -289,15 +283,21 @@
}
/**
- * Check that the version string has some form of "Open GL ES X.Y" in it where X is the major
- * version and Y must be some digit.
+ * Check that the version string has the form "OpenGL ES(-CM)? (\d+)\.(\d+)", where the two
+ * numbers match the major and minor parameters.
*/
- private void assertGlVersionString(int majorVersion) throws InterruptedException {
- String versionString = "" + majorVersion;
- String message = "OpenGL version string '" + mActivity.getVersionString()
- + "' is not " + majorVersion + ".0+.";
- assertTrue(message, Pattern.matches(".*OpenGL.*ES.*" + versionString + "\\.\\d.*",
- mActivity.getVersionString()));
+ private void assertGlVersionString(int major, int minor) throws InterruptedException {
+ Matcher matcher = Pattern.compile("OpenGL ES(?:-CM)? (\\d+)\\.(\\d+).*")
+ .matcher(mActivity.getVersionString());
+ assertTrue("OpenGL ES version string is not of the required form "
+ + "'OpenGL ES(-CM)? (\\d+)\\.(\\d+).*'",
+ matcher.matches());
+ int stringMajor = Integer.parseInt(matcher.group(1));
+ int stringMinor = Integer.parseInt(matcher.group(2));
+ assertEquals("GL_VERSION string doesn't match ActivityManager major version (check ro.opengles.version property)",
+ major, stringMajor);
+ assertEquals("GL_VERSION string doesn't match ActivityManager minor version (check ro.opengles.version property)",
+ minor, stringMinor);
}
/** Restart {@link GLSurfaceViewCtsActivity} with a specific client version. */
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 6f183d5..39d1285 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -30,9 +30,12 @@
# The aim of this package is to run tests against the implementation in use by
# the current android system.
+LOCAL_JAVA_LIBRARIES := cts-core-test-runner
+
LOCAL_STATIC_JAVA_LIBRARIES := \
- cts-core-test-runner \
- android-icu4j-tests
+ android-icu4j-tests \
+ ctstestrunner \
+ android-support-test
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index 7a9504d..4a81a85 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -30,7 +30,7 @@
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_JNI_SHARED_LIBRARIES := libjnitest libnativehelper_compat_libc++
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index fe98bc3..cde0817 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -26,6 +26,7 @@
LOCAL_JAVA_LIBRARIES := bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
core-tests-support \
ctsdeviceutil \
ctstestrunner \
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 879c72b..d61556d 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -44,10 +44,13 @@
# include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
-LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner ndkaudio
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil compatibility-device-util ctstestserver ctstestrunner ndkaudio android-support-test
LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni libaudio_jni libnativehelper_compat_libc++ libndkaudioLib
+# do not compress VP9 video files
+LOCAL_AAPT_FLAGS := -0 .vp9
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsMediaTestCases
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_00.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_00.vp9
new file mode 100644
index 0000000..1d65e32
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_00.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_00_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_00_vp9_md5
new file mode 100644
index 0000000..aa90d5a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_00_vp9_md5
@@ -0,0 +1,2 @@
+c3fbb7abbdb5bd4ed4a7e34768c17df1 vp90-2-00-quantizer-00-352x288-0001.i420
+08203c2595bdb2d58ead6f921345d699 vp90-2-00-quantizer-00-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_01.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_01.vp9
new file mode 100644
index 0000000..c2aebcf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_01.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_01_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_01_vp9_md5
new file mode 100644
index 0000000..85e12ba
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_01_vp9_md5
@@ -0,0 +1,2 @@
+f041b870cf9236d5f22e2b08a77d5958 vp90-2-00-quantizer-01-352x288-0001.i420
+cbdb7526986ae15592891488c9afc84c vp90-2-00-quantizer-01-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_02.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_02.vp9
new file mode 100644
index 0000000..6baa992
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_02.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_02_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_02_vp9_md5
new file mode 100644
index 0000000..e1bbcaa
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_02_vp9_md5
@@ -0,0 +1,2 @@
+98048cfdb4af5059f4085c5acc94ef8f vp90-2-00-quantizer-02-352x288-0001.i420
+8160183e1eed1d0af4427be216b8b9f7 vp90-2-00-quantizer-02-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_03.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_03.vp9
new file mode 100644
index 0000000..7b7ead0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_03.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_03_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_03_vp9_md5
new file mode 100644
index 0000000..fb6f597
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_03_vp9_md5
@@ -0,0 +1,2 @@
+15c548208f5eda243a151a42f4d64855 vp90-2-00-quantizer-03-352x288-0001.i420
+e96d463dc8e9b27b1c2ec40f77eee6ef vp90-2-00-quantizer-03-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_04.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_04.vp9
new file mode 100644
index 0000000..4eb17d0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_04.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_04_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_04_vp9_md5
new file mode 100644
index 0000000..fbe7558
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_04_vp9_md5
@@ -0,0 +1,2 @@
+928c64a0747ac57ab50c1520d694fea7 vp90-2-00-quantizer-04-352x288-0001.i420
+a6f6daa293231e95ef30ed168f582c84 vp90-2-00-quantizer-04-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_05.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_05.vp9
new file mode 100644
index 0000000..b11f071
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_05.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_05_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_05_vp9_md5
new file mode 100644
index 0000000..4977060
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_05_vp9_md5
@@ -0,0 +1,2 @@
+082460718b7d7046c8fb23184b7f71ca vp90-2-00-quantizer-05-352x288-0001.i420
+4a41aad51c40a92df72333e13f47d3fe vp90-2-00-quantizer-05-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_06.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_06.vp9
new file mode 100644
index 0000000..11e2814
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_06.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_06_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_06_vp9_md5
new file mode 100644
index 0000000..2a90a40
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_06_vp9_md5
@@ -0,0 +1,2 @@
+cfca1bed96ff62a69b2d841fda01c6b9 vp90-2-00-quantizer-06-352x288-0001.i420
+9b4d61f1b998745c108f8eb67925e03d vp90-2-00-quantizer-06-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_07.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_07.vp9
new file mode 100644
index 0000000..38f752c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_07.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_07_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_07_vp9_md5
new file mode 100644
index 0000000..6b77e7f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_07_vp9_md5
@@ -0,0 +1,2 @@
+6f5122064bead9d9882bec2698a6ed9c vp90-2-00-quantizer-07-352x288-0001.i420
+50dae67d2f57a76eece210dee8b6df9e vp90-2-00-quantizer-07-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_08.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_08.vp9
new file mode 100644
index 0000000..a666e85
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_08_vp9_md5
new file mode 100644
index 0000000..d0dba67
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_08_vp9_md5
@@ -0,0 +1,2 @@
+eb3d6985fcda5d93dd62d53354e8a093 vp90-2-00-quantizer-08-352x288-0001.i420
+5b1f5b7780b4cafe1f75e56a0b526643 vp90-2-00-quantizer-08-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_09.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_09.vp9
new file mode 100644
index 0000000..d5e9268
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_09.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_09_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_09_vp9_md5
new file mode 100644
index 0000000..a1d78c2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_09_vp9_md5
@@ -0,0 +1,2 @@
+d7ccaf28c59875fe91983def5490d2b1 vp90-2-00-quantizer-09-352x288-0001.i420
+bd98fe9492054826748de840b4495309 vp90-2-00-quantizer-09-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_10.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_10.vp9
new file mode 100644
index 0000000..ad74ec5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_10_vp9_md5
new file mode 100644
index 0000000..cc8a716
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_10_vp9_md5
@@ -0,0 +1,2 @@
+20dda6231f9801c9c237c6d09d9939b6 vp90-2-00-quantizer-10-352x288-0001.i420
+23c91e93807fb9a4ed5bd5bdd449d99f vp90-2-00-quantizer-10-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_11.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_11.vp9
new file mode 100644
index 0000000..144a555
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_11.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_11_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_11_vp9_md5
new file mode 100644
index 0000000..39464f2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_11_vp9_md5
@@ -0,0 +1,2 @@
+960833315ebcdee97f46c4d98d0f3fef vp90-2-00-quantizer-11-352x288-0001.i420
+eec40507d17b64b7895a61cb87b2096a vp90-2-00-quantizer-11-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_12.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_12.vp9
new file mode 100644
index 0000000..c831b57
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_12.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_12_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_12_vp9_md5
new file mode 100644
index 0000000..57e7dbe
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_12_vp9_md5
@@ -0,0 +1,2 @@
+6533224d3b6ba1ec0dd973bbe56c6349 vp90-2-00-quantizer-12-352x288-0001.i420
+12ceadc6d28327a24a75f8c40b6084d1 vp90-2-00-quantizer-12-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_13.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_13.vp9
new file mode 100644
index 0000000..168bca9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_13.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_13_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_13_vp9_md5
new file mode 100644
index 0000000..03acb52
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_13_vp9_md5
@@ -0,0 +1,2 @@
+7268de6756014f79a56dcf010c52a97f vp90-2-00-quantizer-13-352x288-0001.i420
+9e39e9b0e2295b8460dfa05f44762771 vp90-2-00-quantizer-13-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_14.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_14.vp9
new file mode 100644
index 0000000..0113e12
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_14.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_14_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_14_vp9_md5
new file mode 100644
index 0000000..2525db5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_14_vp9_md5
@@ -0,0 +1,2 @@
+57e9e333c641fa952f7485b788df225a vp90-2-00-quantizer-14-352x288-0001.i420
+551f0cea83dcdf4540c3983736757874 vp90-2-00-quantizer-14-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_15.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_15.vp9
new file mode 100644
index 0000000..fe7add2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_15.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_15_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_15_vp9_md5
new file mode 100644
index 0000000..c6e5377
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_15_vp9_md5
@@ -0,0 +1,2 @@
+17a0a2842856b9e89aede237648d5dda vp90-2-00-quantizer-15-352x288-0001.i420
+c9fcade888a38621bebe3d4b41664245 vp90-2-00-quantizer-15-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_16.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_16.vp9
new file mode 100644
index 0000000..c9c35b4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_16_vp9_md5
new file mode 100644
index 0000000..c1abf24
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_16_vp9_md5
@@ -0,0 +1,2 @@
+6cc2089e9a3d352fe10b59ccd935c677 vp90-2-00-quantizer-16-352x288-0001.i420
+d165bf7b9cb901e121a65038758d8613 vp90-2-00-quantizer-16-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_17.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_17.vp9
new file mode 100644
index 0000000..cd8dd67
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_17.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_17_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_17_vp9_md5
new file mode 100644
index 0000000..40d8f03
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_17_vp9_md5
@@ -0,0 +1,2 @@
+bc80511c83162c09661f155cd29f6dd8 vp90-2-00-quantizer-17-352x288-0001.i420
+a62f1cbdb3f86d2fb4c880cfd917def5 vp90-2-00-quantizer-17-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_18.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_18.vp9
new file mode 100644
index 0000000..4b0fe9f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_18_vp9_md5
new file mode 100644
index 0000000..3cb5fbe
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_18_vp9_md5
@@ -0,0 +1,2 @@
+b2d350f6faa41cb50c2e8a9907d0f4a5 vp90-2-00-quantizer-18-352x288-0001.i420
+39b4380d16bc8e093dd4dba475175fb3 vp90-2-00-quantizer-18-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_19.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_19.vp9
new file mode 100644
index 0000000..f14d8d6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_19.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_19_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_19_vp9_md5
new file mode 100644
index 0000000..36dbdac
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_19_vp9_md5
@@ -0,0 +1,2 @@
+441e09be3c15fcb240afd74bb7a10a72 vp90-2-00-quantizer-19-352x288-0001.i420
+32ae5dac876ca5d5ae6ab7c74f4dc25d vp90-2-00-quantizer-19-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_20.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_20.vp9
new file mode 100644
index 0000000..062fd61
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_20.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_20_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_20_vp9_md5
new file mode 100644
index 0000000..ca80f66
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_20_vp9_md5
@@ -0,0 +1,2 @@
+7786eb9944dba0553e129133523a98c1 vp90-2-00-quantizer-20-352x288-0001.i420
+206d888f8453427f10a40aa8bf5f6df0 vp90-2-00-quantizer-20-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_21.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_21.vp9
new file mode 100644
index 0000000..500950c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_21.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_21_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_21_vp9_md5
new file mode 100644
index 0000000..b31ac9e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_21_vp9_md5
@@ -0,0 +1,2 @@
+aab95e195be71feca050a839d7b3154d vp90-2-00-quantizer-21-352x288-0001.i420
+02a05d699bbbdc477e34bb0dad9f0391 vp90-2-00-quantizer-21-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_22.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_22.vp9
new file mode 100644
index 0000000..88dad68
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_22.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_22_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_22_vp9_md5
new file mode 100644
index 0000000..8f50f51
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_22_vp9_md5
@@ -0,0 +1,2 @@
+41f853c3ee2d4611b645cc643d82e287 vp90-2-00-quantizer-22-352x288-0001.i420
+1c240c653110ff8609ca0f0287a6496d vp90-2-00-quantizer-22-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_23.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_23.vp9
new file mode 100644
index 0000000..1834017
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_23.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_23_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_23_vp9_md5
new file mode 100644
index 0000000..ea0aaaa
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_23_vp9_md5
@@ -0,0 +1,2 @@
+bc5b07369df50c8f97ce1a377fe513cf vp90-2-00-quantizer-23-352x288-0001.i420
+ce62ddb4f3e305d0f8587ae8bb44cc79 vp90-2-00-quantizer-23-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_24.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_24.vp9
new file mode 100644
index 0000000..d9dac53
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_24.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_24_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_24_vp9_md5
new file mode 100644
index 0000000..49f378f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_24_vp9_md5
@@ -0,0 +1,2 @@
+982d54041221c977b6f0e37a9236cc76 vp90-2-00-quantizer-24-352x288-0001.i420
+57631e7f13f645c834e2944ebfd6d40e vp90-2-00-quantizer-24-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_25.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_25.vp9
new file mode 100644
index 0000000..e04f1b6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_25.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_25_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_25_vp9_md5
new file mode 100644
index 0000000..90ed556
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_25_vp9_md5
@@ -0,0 +1,2 @@
+b0fb55f3f2f56b3d27038e83c10123ce vp90-2-00-quantizer-25-352x288-0001.i420
+9fcac3becdcc2d30d778a55eca4c2018 vp90-2-00-quantizer-25-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_26.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_26.vp9
new file mode 100644
index 0000000..3b5abd3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_26.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_26_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_26_vp9_md5
new file mode 100644
index 0000000..dbec99c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_26_vp9_md5
@@ -0,0 +1,2 @@
+4f645e0f354da77b9e2f2a6753c361da vp90-2-00-quantizer-26-352x288-0001.i420
+b7542998ec298273ca662bc9b658d10e vp90-2-00-quantizer-26-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_27.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_27.vp9
new file mode 100644
index 0000000..6dbea83
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_27.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_27_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_27_vp9_md5
new file mode 100644
index 0000000..14ec691
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_27_vp9_md5
@@ -0,0 +1,2 @@
+6edc96a3747cad43828397045764206e vp90-2-00-quantizer-27-352x288-0001.i420
+5fbc65d20fdca1abd69079851ce676d3 vp90-2-00-quantizer-27-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_28.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_28.vp9
new file mode 100644
index 0000000..8f928cc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_28.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_28_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_28_vp9_md5
new file mode 100644
index 0000000..0e2d177
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_28_vp9_md5
@@ -0,0 +1,2 @@
+5db3e910e70da38bb91d01d73acc33dd vp90-2-00-quantizer-28-352x288-0001.i420
+b920ee7f7e61b7fdf9f44b1f738d0292 vp90-2-00-quantizer-28-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_29.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_29.vp9
new file mode 100644
index 0000000..f343340
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_29.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_29_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_29_vp9_md5
new file mode 100644
index 0000000..1187388
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_29_vp9_md5
@@ -0,0 +1,2 @@
+3cb3e310be5305077efa6216f6f10654 vp90-2-00-quantizer-29-352x288-0001.i420
+692d3e098af5978fe1a898ebc1a66a7a vp90-2-00-quantizer-29-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_30.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_30.vp9
new file mode 100644
index 0000000..f6ce3c8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_30.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_30_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_30_vp9_md5
new file mode 100644
index 0000000..39a6f82
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_30_vp9_md5
@@ -0,0 +1,2 @@
+e3b3cea66ea38c5dfba1aa73bb4c611d vp90-2-00-quantizer-30-352x288-0001.i420
+42bb3e54b19c3f4c4f7ee3a6ba012e19 vp90-2-00-quantizer-30-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_31.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_31.vp9
new file mode 100644
index 0000000..e83141f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_31.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_31_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_31_vp9_md5
new file mode 100644
index 0000000..9d84937
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_31_vp9_md5
@@ -0,0 +1,2 @@
+2523e9ecfd3781eafcd7da192dc105e9 vp90-2-00-quantizer-31-352x288-0001.i420
+6d5feea012b9a1f51fc643633e728764 vp90-2-00-quantizer-31-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_32.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_32.vp9
new file mode 100644
index 0000000..5987ec8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_32_vp9_md5
new file mode 100644
index 0000000..5e6cdde
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_32_vp9_md5
@@ -0,0 +1,2 @@
+0a0305eba36500ebf6cc6cc0f01f5a3b vp90-2-00-quantizer-32-352x288-0001.i420
+2c76bcd6763467f9057a726fbcf50ab1 vp90-2-00-quantizer-32-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_33.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_33.vp9
new file mode 100644
index 0000000..c053597
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_33.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_33_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_33_vp9_md5
new file mode 100644
index 0000000..4604865
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_33_vp9_md5
@@ -0,0 +1,2 @@
+c68433e0e94047c220be9b629334f744 vp90-2-00-quantizer-33-352x288-0001.i420
+fcfa4dff7a39bc9c5e315849ecbb46ea vp90-2-00-quantizer-33-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_34.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_34.vp9
new file mode 100644
index 0000000..3b13d0c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_34_vp9_md5
new file mode 100644
index 0000000..42ec3bd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_34_vp9_md5
@@ -0,0 +1,2 @@
+ad9dc2f912c137b014a33e2792c88a25 vp90-2-00-quantizer-34-352x288-0001.i420
+11221ee4ea5c776f43af68756682cd5a vp90-2-00-quantizer-34-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_35.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_35.vp9
new file mode 100644
index 0000000..9e88eaf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_35.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_35_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_35_vp9_md5
new file mode 100644
index 0000000..7467703
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_35_vp9_md5
@@ -0,0 +1,2 @@
+75031f898cccf303a64ab46b1f815389 vp90-2-00-quantizer-35-352x288-0001.i420
+a4fc864e7fbc470dfcab6207e0eea152 vp90-2-00-quantizer-35-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_36.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_36.vp9
new file mode 100644
index 0000000..89095d8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_36.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_36_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_36_vp9_md5
new file mode 100644
index 0000000..f83c5fd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_36_vp9_md5
@@ -0,0 +1,2 @@
+c7824af009fde6cafdd8d39fae6bb6cf vp90-2-00-quantizer-36-352x288-0001.i420
+516a82d5fc4dfa3daf713ed2ec36041b vp90-2-00-quantizer-36-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_37.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_37.vp9
new file mode 100644
index 0000000..51ea020
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_37.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_37_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_37_vp9_md5
new file mode 100644
index 0000000..56ae9cf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_37_vp9_md5
@@ -0,0 +1,2 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-00-quantizer-37-352x288-0001.i420
+fb23e0bc64728a492a33d985032f21b8 vp90-2-00-quantizer-37-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_38.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_38.vp9
new file mode 100644
index 0000000..b502d01
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_38.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_38_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_38_vp9_md5
new file mode 100644
index 0000000..5c70650
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_38_vp9_md5
@@ -0,0 +1,2 @@
+8347bfb891317e89ef66781d6c28e24f vp90-2-00-quantizer-38-352x288-0001.i420
+a5722f824d32deac042513a1a7dcdcd0 vp90-2-00-quantizer-38-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_39.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_39.vp9
new file mode 100644
index 0000000..559a435
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_39.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_39_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_39_vp9_md5
new file mode 100644
index 0000000..7c9fece
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_39_vp9_md5
@@ -0,0 +1,2 @@
+018968f97fac3bdff146cf22c1da5ef0 vp90-2-00-quantizer-39-352x288-0001.i420
+ca8b09b01e5132183395e238f1c7901e vp90-2-00-quantizer-39-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_40.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_40.vp9
new file mode 100644
index 0000000..2cbb549
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_40.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_40_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_40_vp9_md5
new file mode 100644
index 0000000..6b3c92a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_40_vp9_md5
@@ -0,0 +1,2 @@
+792660f6589ad5340be4bd0554435866 vp90-2-00-quantizer-40-352x288-0001.i420
+68c84c8a15d679e0a73678b93215c62c vp90-2-00-quantizer-40-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_41.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_41.vp9
new file mode 100644
index 0000000..910d486
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_41.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_41_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_41_vp9_md5
new file mode 100644
index 0000000..7df4a7f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_41_vp9_md5
@@ -0,0 +1,2 @@
+a456bdfc6c1c07b4cb3a3848843743b9 vp90-2-00-quantizer-41-352x288-0001.i420
+fe41a12b8cb6bc5667ba2179e076f3b0 vp90-2-00-quantizer-41-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_42.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_42.vp9
new file mode 100644
index 0000000..53c6b55
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_42.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_42_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_42_vp9_md5
new file mode 100644
index 0000000..4abe677
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_42_vp9_md5
@@ -0,0 +1,2 @@
+f016dd8431694d989700fb1ba71a5b2d vp90-2-00-quantizer-42-352x288-0001.i420
+e89c3c5b935157b40f2fb0ab92415828 vp90-2-00-quantizer-42-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_43.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_43.vp9
new file mode 100644
index 0000000..0d3e706
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_43.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_43_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_43_vp9_md5
new file mode 100644
index 0000000..2db4096
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_43_vp9_md5
@@ -0,0 +1,2 @@
+7b8ab82625f3006bac89d4fb5197e71c vp90-2-00-quantizer-43-352x288-0001.i420
+18bd3716045563dfba2c72b640b3274b vp90-2-00-quantizer-43-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_44.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_44.vp9
new file mode 100644
index 0000000..4b1c580
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_44.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_44_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_44_vp9_md5
new file mode 100644
index 0000000..aa705be
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_44_vp9_md5
@@ -0,0 +1,2 @@
+66fde04d8320c750e56406feefd29979 vp90-2-00-quantizer-44-352x288-0001.i420
+f9d01d8fc1722ec345e624e14b404215 vp90-2-00-quantizer-44-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_45.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_45.vp9
new file mode 100644
index 0000000..12779d6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_45.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_45_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_45_vp9_md5
new file mode 100644
index 0000000..4472c2f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_45_vp9_md5
@@ -0,0 +1,2 @@
+cc97597b015896d73f3e60e7ae44c4da vp90-2-00-quantizer-45-352x288-0001.i420
+fea98bc508f92135641ab99762444b14 vp90-2-00-quantizer-45-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_46.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_46.vp9
new file mode 100644
index 0000000..8f1aff1
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_46.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_46_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_46_vp9_md5
new file mode 100644
index 0000000..bb306b1
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_46_vp9_md5
@@ -0,0 +1,2 @@
+79ed95c741178bb3c0954f1f6f8e21a3 vp90-2-00-quantizer-46-352x288-0001.i420
+f02a06a5e2b5b7619c9a52c5bea0564d vp90-2-00-quantizer-46-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_47.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_47.vp9
new file mode 100644
index 0000000..e8d81b4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_47.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_47_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_47_vp9_md5
new file mode 100644
index 0000000..5734952
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_47_vp9_md5
@@ -0,0 +1,2 @@
+9b98e948b8c2a822f21bd8419e6f4410 vp90-2-00-quantizer-47-352x288-0001.i420
+491382d68c16c2a3c6f1746598bc4a97 vp90-2-00-quantizer-47-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_48.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_48.vp9
new file mode 100644
index 0000000..9644566
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_48.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_48_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_48_vp9_md5
new file mode 100644
index 0000000..0b79523
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_48_vp9_md5
@@ -0,0 +1,2 @@
+f0f095b0edae7262f44d7ed7ef84ded4 vp90-2-00-quantizer-48-352x288-0001.i420
+0e833889ccac81d60251007d1baf6500 vp90-2-00-quantizer-48-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_49.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_49.vp9
new file mode 100644
index 0000000..c0efd85
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_49.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_49_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_49_vp9_md5
new file mode 100644
index 0000000..72f8300
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_49_vp9_md5
@@ -0,0 +1,2 @@
+6c1b7b7827617fb9b8417aca2cfdbcaa vp90-2-00-quantizer-49-352x288-0001.i420
+4c1fc8a89297fdcf79f0faabd42b8684 vp90-2-00-quantizer-49-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_50.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_50.vp9
new file mode 100644
index 0000000..3797305
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_50.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_50_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_50_vp9_md5
new file mode 100644
index 0000000..f104046
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_50_vp9_md5
@@ -0,0 +1,2 @@
+ca6142db68463487bc28c888ab38476c vp90-2-00-quantizer-50-352x288-0001.i420
+02a71153ec70f569524c3d814cb62f86 vp90-2-00-quantizer-50-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_51.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_51.vp9
new file mode 100644
index 0000000..ad66216
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_51.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_51_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_51_vp9_md5
new file mode 100644
index 0000000..7874a6f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_51_vp9_md5
@@ -0,0 +1,2 @@
+eece2627df1ddf0872256eb92352e179 vp90-2-00-quantizer-51-352x288-0001.i420
+0ee9f221246ad747250e4b5e8ba586e2 vp90-2-00-quantizer-51-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_52.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_52.vp9
new file mode 100644
index 0000000..b729121
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_52.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_52_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_52_vp9_md5
new file mode 100644
index 0000000..d5092d6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_52_vp9_md5
@@ -0,0 +1,2 @@
+7290039d974c4e50db9d69f9864bcdbe vp90-2-00-quantizer-52-352x288-0001.i420
+264765de9d02503038a4da54133b9f85 vp90-2-00-quantizer-52-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_53.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_53.vp9
new file mode 100644
index 0000000..eace52e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_53.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_53_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_53_vp9_md5
new file mode 100644
index 0000000..3566f61
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_53_vp9_md5
@@ -0,0 +1,2 @@
+917af24da66f143a56a01eb2c2254285 vp90-2-00-quantizer-53-352x288-0001.i420
+45a05d3bc644420519619e4115662a70 vp90-2-00-quantizer-53-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_54.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_54.vp9
new file mode 100644
index 0000000..0100c2b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_54.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_54_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_54_vp9_md5
new file mode 100644
index 0000000..96fdd4b6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_54_vp9_md5
@@ -0,0 +1,2 @@
+6fea2820bb10a9dec9add4d2452b01f5 vp90-2-00-quantizer-54-352x288-0001.i420
+74675169a4bfc2ff5463c4db5d85a79f vp90-2-00-quantizer-54-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_55.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_55.vp9
new file mode 100644
index 0000000..d84bbb2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_55.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_55_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_55_vp9_md5
new file mode 100644
index 0000000..ec38867
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_55_vp9_md5
@@ -0,0 +1,2 @@
+11e5d196f6537fb7d85988d90195e556 vp90-2-00-quantizer-55-352x288-0001.i420
+8536106795f7c93c5a43a11493527469 vp90-2-00-quantizer-55-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_56.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_56.vp9
new file mode 100644
index 0000000..befee07
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_56.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_56_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_56_vp9_md5
new file mode 100644
index 0000000..a93ced9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_56_vp9_md5
@@ -0,0 +1,2 @@
+40839b7a3a40ec10f96b8a75224f646d vp90-2-00-quantizer-56-352x288-0001.i420
+11408dd73e8c45ddaab99f5c9650102b vp90-2-00-quantizer-56-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_57.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_57.vp9
new file mode 100644
index 0000000..7df44d5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_57.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_57_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_57_vp9_md5
new file mode 100644
index 0000000..1979cd8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_57_vp9_md5
@@ -0,0 +1,2 @@
+d0e9fa03dd48da4592ebaadb4e3794e0 vp90-2-00-quantizer-57-352x288-0001.i420
+5172e29b1e04cd543833d6a68aab297c vp90-2-00-quantizer-57-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_58.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_58.vp9
new file mode 100644
index 0000000..49a5fa9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_58.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_58_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_58_vp9_md5
new file mode 100644
index 0000000..cb06866
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_58_vp9_md5
@@ -0,0 +1,2 @@
+bef4a27d460e7697e038fe6f1c8bd597 vp90-2-00-quantizer-58-352x288-0001.i420
+124674686cafc5f2ff5bc7ea412b8f3b vp90-2-00-quantizer-58-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_59.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_59.vp9
new file mode 100644
index 0000000..fd50ac3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_59.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_59_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_59_vp9_md5
new file mode 100644
index 0000000..240ea59
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_59_vp9_md5
@@ -0,0 +1,2 @@
+ae9d99e9d16ef20073300559566844ae vp90-2-00-quantizer-59-352x288-0001.i420
+da9405e5a6bfe4ed18d927ba2004008e vp90-2-00-quantizer-59-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_60.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_60.vp9
new file mode 100644
index 0000000..d2caca9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_60.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_60_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_60_vp9_md5
new file mode 100644
index 0000000..550fee9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_60_vp9_md5
@@ -0,0 +1,2 @@
+9e66bb8e1b5e206ea4afe4bf2d335ac5 vp90-2-00-quantizer-60-352x288-0001.i420
+092b74c905c12c1e87e90f5a79857736 vp90-2-00-quantizer-60-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_61.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_61.vp9
new file mode 100644
index 0000000..f20df40
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_61.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_61_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_61_vp9_md5
new file mode 100644
index 0000000..2e3edd3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_61_vp9_md5
@@ -0,0 +1,2 @@
+d062dc6be246c8042744018765ef50a8 vp90-2-00-quantizer-61-352x288-0001.i420
+45fd9cbacb6a91060a7e49a58a85869d vp90-2-00-quantizer-61-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_62.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_62.vp9
new file mode 100644
index 0000000..2b8fd32
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_62.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_62_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_62_vp9_md5
new file mode 100644
index 0000000..1d266b3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_62_vp9_md5
@@ -0,0 +1,2 @@
+62f7e42fe653e81c5a65a25389e045b5 vp90-2-00-quantizer-62-352x288-0001.i420
+cb0cdd0b25689e0a43328550011d960d vp90-2-00-quantizer-62-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_63.vp9 b/tests/tests/media/res/raw/vp90_2_00_quantizer_63.vp9
new file mode 100644
index 0000000..28c2564
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_63.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_00_quantizer_63_vp9_md5 b/tests/tests/media/res/raw/vp90_2_00_quantizer_63_vp9_md5
new file mode 100644
index 0000000..b5d122f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_00_quantizer_63_vp9_md5
@@ -0,0 +1,2 @@
+8467643dceff827e04acd82eeff1d1b0 vp90-2-00-quantizer-63-352x288-0001.i420
+c786f49d66f4dfd685dea9605821a19f vp90-2-00-quantizer-63-352x288-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_1.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_1.vp9
new file mode 100644
index 0000000..dd0f0ee
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_1.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_1_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_1_vp9_md5
new file mode 100644
index 0000000..1db2ed2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_1_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-1-352x288-0001.i420
+aa20a75be3a316193496706c9f760d08 vp90-2-01-sharpness-1-352x288-0002.i420
+95567be97a64d3c9efe45f2524116a2e vp90-2-01-sharpness-1-352x288-0003.i420
+219e86cd6b3cca312856eead21776b1c vp90-2-01-sharpness-1-352x288-0004.i420
+4a67fd359ca362398e97c15eb018a2bb vp90-2-01-sharpness-1-352x288-0005.i420
+9916d4e359274d690827f0eb22547423 vp90-2-01-sharpness-1-352x288-0006.i420
+a07785b52561150c48f1a8eff89d5d75 vp90-2-01-sharpness-1-352x288-0007.i420
+a3382a92982953dfa20018e5ac975b51 vp90-2-01-sharpness-1-352x288-0008.i420
+911836989ca7b148438aa3ec7fc7e303 vp90-2-01-sharpness-1-352x288-0009.i420
+5627b981e3fc9e4401d35d3a5ab25917 vp90-2-01-sharpness-1-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_2.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_2.vp9
new file mode 100644
index 0000000..d1d1a06
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_2.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_2_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_2_vp9_md5
new file mode 100644
index 0000000..cb4d78e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_2_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-2-352x288-0001.i420
+cd94572239817ae7c9b07de739c3272b vp90-2-01-sharpness-2-352x288-0002.i420
+383cf752d457e122b5ff49d08960208e vp90-2-01-sharpness-2-352x288-0003.i420
+1c0a6ec9cd3ce29b8b004e7526f1b07e vp90-2-01-sharpness-2-352x288-0004.i420
+91c42a8a108d67947cabfc2a5a80df66 vp90-2-01-sharpness-2-352x288-0005.i420
+08c57fc1f3fec0305883315a66c714d1 vp90-2-01-sharpness-2-352x288-0006.i420
+70cb8d8dc83eac82f2d3c4b0376bb1aa vp90-2-01-sharpness-2-352x288-0007.i420
+ffd62a9ef829ec81f0f74f740488a41f vp90-2-01-sharpness-2-352x288-0008.i420
+bab0aa23b5854e2a70926046e4618710 vp90-2-01-sharpness-2-352x288-0009.i420
+fec456f38f2a43661e786a8d5f67ed15 vp90-2-01-sharpness-2-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_3.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_3.vp9
new file mode 100644
index 0000000..ac4d3c7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_3.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_3_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_3_vp9_md5
new file mode 100644
index 0000000..5f66ebd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_3_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-3-352x288-0001.i420
+0d487a146393a0b8b84b4be1b371b507 vp90-2-01-sharpness-3-352x288-0002.i420
+68372e191eba620a431cfff226026ac3 vp90-2-01-sharpness-3-352x288-0003.i420
+de7fd274460e36b983fe93acc208d72f vp90-2-01-sharpness-3-352x288-0004.i420
+afbd36c61bab65b98ff9acf08e215721 vp90-2-01-sharpness-3-352x288-0005.i420
+e1e9fc2ab4e7a187a8d8d84aae48d6b9 vp90-2-01-sharpness-3-352x288-0006.i420
+11d95de6a9cc5e00511e99534779faac vp90-2-01-sharpness-3-352x288-0007.i420
+cd2f5539fdfc2d8eefe6b6da28c13398 vp90-2-01-sharpness-3-352x288-0008.i420
+a8b3aeed41da7aeb8d5b962ee4a4af93 vp90-2-01-sharpness-3-352x288-0009.i420
+4283670bd1c1c506ef18d3dafca22035 vp90-2-01-sharpness-3-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_4.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_4.vp9
new file mode 100644
index 0000000..4f9ac94
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_4.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_4_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_4_vp9_md5
new file mode 100644
index 0000000..dc3f2c1
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_4_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-4-352x288-0001.i420
+8bad76c55b5149169d64ce6512521de6 vp90-2-01-sharpness-4-352x288-0002.i420
+c1d986e1f9bf46382e598ba289b9bd7c vp90-2-01-sharpness-4-352x288-0003.i420
+86c097ac6069c786023d3561dae68bac vp90-2-01-sharpness-4-352x288-0004.i420
+8c238a2831b8c7c49736b6de6ff76ed8 vp90-2-01-sharpness-4-352x288-0005.i420
+cb5a038ed0a74a317ee72dae93a7ee3e vp90-2-01-sharpness-4-352x288-0006.i420
+f8fe330a257e3e4e4c39c1c12820a654 vp90-2-01-sharpness-4-352x288-0007.i420
+a73e2fcdcbb9334c0c123f8276a2c881 vp90-2-01-sharpness-4-352x288-0008.i420
+24fccece8ee639e4d0e00e4060e1db0c vp90-2-01-sharpness-4-352x288-0009.i420
+46d6e9aad69a39c718c5fd1e41e86e6e vp90-2-01-sharpness-4-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_5.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_5.vp9
new file mode 100644
index 0000000..7f5e528
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_5.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_5_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_5_vp9_md5
new file mode 100644
index 0000000..a545e7c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_5_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-5-352x288-0001.i420
+f1ce0a5d57a46c9ff1331804b7b03fdb vp90-2-01-sharpness-5-352x288-0002.i420
+0364a085b06bee6b980189cf5378eda9 vp90-2-01-sharpness-5-352x288-0003.i420
+4b5358698d734b0ae210909a913d4c1e vp90-2-01-sharpness-5-352x288-0004.i420
+dc22565aaceee77b15fd8ab3c84bd5e0 vp90-2-01-sharpness-5-352x288-0005.i420
+5f6340b656536292b46ba9a647aeb6e4 vp90-2-01-sharpness-5-352x288-0006.i420
+b7d4bce9a04b2a6caa45801be15e331e vp90-2-01-sharpness-5-352x288-0007.i420
+534c851cfe59ffc047815ece98d8cede vp90-2-01-sharpness-5-352x288-0008.i420
+786b0e1564d5c71aabfc2dd528cff4e7 vp90-2-01-sharpness-5-352x288-0009.i420
+cac0366209cf471bb7cc3e64966cbbd4 vp90-2-01-sharpness-5-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_6.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_6.vp9
new file mode 100644
index 0000000..5f8d031
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_6.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_6_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_6_vp9_md5
new file mode 100644
index 0000000..0c36072
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_6_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-6-352x288-0001.i420
+45d9ca07ed04210b1ebc743169bc8ec4 vp90-2-01-sharpness-6-352x288-0002.i420
+5b646cc309a711f1d8814f925002d8c4 vp90-2-01-sharpness-6-352x288-0003.i420
+34db8db727fa1ded0a55cc7cf85be249 vp90-2-01-sharpness-6-352x288-0004.i420
+54173d08afe6369b16a9c0c9cc6ce04d vp90-2-01-sharpness-6-352x288-0005.i420
+76275b0a478cdb3c1fb527ebbce023c3 vp90-2-01-sharpness-6-352x288-0006.i420
+e7643cdf0c42f2af700d8730bfc1a453 vp90-2-01-sharpness-6-352x288-0007.i420
+6e53097e56f680cb658d63100e7736f7 vp90-2-01-sharpness-6-352x288-0008.i420
+1a407c3c8ea1d5245ae68c5ce7de70e1 vp90-2-01-sharpness-6-352x288-0009.i420
+6cbca24912cadf09b20be74f14e359c9 vp90-2-01-sharpness-6-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_7.vp9 b/tests/tests/media/res/raw/vp90_2_01_sharpness_7.vp9
new file mode 100644
index 0000000..325523f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_7.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_01_sharpness_7_vp9_md5 b/tests/tests/media/res/raw/vp90_2_01_sharpness_7_vp9_md5
new file mode 100644
index 0000000..6c94a52
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_01_sharpness_7_vp9_md5
@@ -0,0 +1,10 @@
+a2e5c820fd9733e18f9349fb658ca281 vp90-2-01-sharpness-7-352x288-0001.i420
+f719d0be18d16a448b4e7da3e2d9bf28 vp90-2-01-sharpness-7-352x288-0002.i420
+83ee8ebc0ca796782a2376a76f2ffc26 vp90-2-01-sharpness-7-352x288-0003.i420
+7cf5afdbc229e1af50a5377cfc23d831 vp90-2-01-sharpness-7-352x288-0004.i420
+44244e896e0362f6376ba5afa563ba8b vp90-2-01-sharpness-7-352x288-0005.i420
+df5f518d44eb6cb91b2df5a30d27ef82 vp90-2-01-sharpness-7-352x288-0006.i420
+43cc3f151b8337aca7ee659c8abeb783 vp90-2-01-sharpness-7-352x288-0007.i420
+4e89573470d9b97464e10806fc81aa8b vp90-2-01-sharpness-7-352x288-0008.i420
+62e0ba70f07ece8d85372f0a42e83a9a vp90-2-01-sharpness-7-352x288-0009.i420
+45ac2928acb11326f6c4a21401f3609c vp90-2-01-sharpness-7-352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x08.vp9
new file mode 100644
index 0000000..269acbb
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x08_vp9_md5
new file mode 100644
index 0000000..c74db82
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x08_vp9_md5
@@ -0,0 +1,10 @@
+52def242c36123e5a8f5f53d6a971399 vp90-2-02-size-08x08-8x8-0001.i420
+79c93360fbd47179400414bbfee0901c vp90-2-02-size-08x08-8x8-0002.i420
+c3b1947c79537baa7838905276276a91 vp90-2-02-size-08x08-8x8-0003.i420
+20f35e501bdee0bc63e87b9240265c25 vp90-2-02-size-08x08-8x8-0004.i420
+5e8f1c464bafd54833c51860906b5368 vp90-2-02-size-08x08-8x8-0005.i420
+f57b592600dfc99e634a083278af769a vp90-2-02-size-08x08-8x8-0006.i420
+7b02191f85590cbad3f148c7b92d6436 vp90-2-02-size-08x08-8x8-0007.i420
+b0a1c9870447a1744f64cd4087ef55ee vp90-2-02-size-08x08-8x8-0008.i420
+c82712b1ba7a95efb67cbdde0ad708b6 vp90-2-02-size-08x08-8x8-0009.i420
+89f4539f8d7a7b45a91fd2f46335988e vp90-2-02-size-08x08-8x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x10.vp9
new file mode 100644
index 0000000..714467a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x10_vp9_md5
new file mode 100644
index 0000000..c051eb9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x10_vp9_md5
@@ -0,0 +1,10 @@
+ea3e0f807304b0eb2d3e329b0124f75c vp90-2-02-size-08x10-8x10-0001.i420
+8d13cf682d63e7eb13094f55d67fc458 vp90-2-02-size-08x10-8x10-0002.i420
+e729cc6c3684c94a8f6118c618efc3ea vp90-2-02-size-08x10-8x10-0003.i420
+ac43a0ace8e4112e877c2491ecc14fb5 vp90-2-02-size-08x10-8x10-0004.i420
+53695f90b88d8e8cb838f0faec3238d3 vp90-2-02-size-08x10-8x10-0005.i420
+40afd1c4dfd4a2e3b31631c46d252bcc vp90-2-02-size-08x10-8x10-0006.i420
+2b656f76f2e84d2f82d9bda2b5be94d3 vp90-2-02-size-08x10-8x10-0007.i420
+b22f004d678d047bc401be5e040cf883 vp90-2-02-size-08x10-8x10-0008.i420
+57c840319abfb9c31013fbde54de3fb0 vp90-2-02-size-08x10-8x10-0009.i420
+0f3dfc156216d7cfb6fd1d8c77dadab9 vp90-2-02-size-08x10-8x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x16.vp9
new file mode 100644
index 0000000..815483f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x16_vp9_md5
new file mode 100644
index 0000000..d95f639
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x16_vp9_md5
@@ -0,0 +1,10 @@
+0553e56a9d89aea496421885aab491f5 vp90-2-02-size-08x16-8x16-0001.i420
+b2a14cf676f7ebf3c50450050f76ad16 vp90-2-02-size-08x16-8x16-0002.i420
+a308d981e09b50571fb0c8ebdcefe505 vp90-2-02-size-08x16-8x16-0003.i420
+d592ec625a0ac0373e82610c3eed9864 vp90-2-02-size-08x16-8x16-0004.i420
+acd19642455e643023b4fb882c3891ba vp90-2-02-size-08x16-8x16-0005.i420
+5af5390fd8c29b795e0ddf83f3f34284 vp90-2-02-size-08x16-8x16-0006.i420
+473505aa2a76231725cf2107d6c9dbef vp90-2-02-size-08x16-8x16-0007.i420
+84860db6887e320f2d64f80cf0032e57 vp90-2-02-size-08x16-8x16-0008.i420
+408e9cf60e99ae99d204ff08f3196d1a vp90-2-02-size-08x16-8x16-0009.i420
+d8af96b79258f9382e911ed38340bdf5 vp90-2-02-size-08x16-8x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x18.vp9
new file mode 100644
index 0000000..542ae03
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x18_vp9_md5
new file mode 100644
index 0000000..d22d06a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x18_vp9_md5
@@ -0,0 +1,10 @@
+4c41f93b1b280b37bc77d7047435eaa4 vp90-2-02-size-08x18-8x18-0001.i420
+c9c80fdba2ebc2b8c3490ae35e34f84f vp90-2-02-size-08x18-8x18-0002.i420
+089d86acb3263fa5ef4f591a7f44556d vp90-2-02-size-08x18-8x18-0003.i420
+938fca6d93b83484144f5054e4838a41 vp90-2-02-size-08x18-8x18-0004.i420
+e0592e2ac9f5e09525ce0d3904cadf47 vp90-2-02-size-08x18-8x18-0005.i420
+ea43ff5d1330986e60c08567262ea764 vp90-2-02-size-08x18-8x18-0006.i420
+08b40fe109ee90188f1cba9bbb1b376e vp90-2-02-size-08x18-8x18-0007.i420
+b067068a2a7e36d5c5b5b405a1e73a18 vp90-2-02-size-08x18-8x18-0008.i420
+9cf2d350296288803434b7451bd2be85 vp90-2-02-size-08x18-8x18-0009.i420
+3c785e21dc228d6396738fbfcb470289 vp90-2-02-size-08x18-8x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x32.vp9
new file mode 100644
index 0000000..57dafca
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x32_vp9_md5
new file mode 100644
index 0000000..32a5a7b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x32_vp9_md5
@@ -0,0 +1,10 @@
+f92a7777fd69aa2f2914d9a41c4828ba vp90-2-02-size-08x32-8x32-0001.i420
+62e1cc73487d2249a88a60e35a22d9c7 vp90-2-02-size-08x32-8x32-0002.i420
+aa2619b605cb65eda15fdd99d5775550 vp90-2-02-size-08x32-8x32-0003.i420
+e6f0a491c543b835d0cefe5ca62c3dbe vp90-2-02-size-08x32-8x32-0004.i420
+361be1a06913c398f09494ca1b2d288f vp90-2-02-size-08x32-8x32-0005.i420
+0497bf849a973357c0ccb8d43f5bd8b4 vp90-2-02-size-08x32-8x32-0006.i420
+5ac6ac523147c409dd00820622161dd7 vp90-2-02-size-08x32-8x32-0007.i420
+7d07245574a46c524360f09be29a5f19 vp90-2-02-size-08x32-8x32-0008.i420
+fcfa7fbcaf42f81e4e34a4ee5a029ca1 vp90-2-02-size-08x32-8x32-0009.i420
+336e3fe4f15d3d6c82d82b1855dcfeb4 vp90-2-02-size-08x32-8x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x34.vp9
new file mode 100644
index 0000000..68ff21f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x34_vp9_md5
new file mode 100644
index 0000000..626dce9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x34_vp9_md5
@@ -0,0 +1,10 @@
+f3f2cd8f157466ff23dace85d77367ce vp90-2-02-size-08x34-8x34-0001.i420
+639d9b70a14062e95559c12d2b597f91 vp90-2-02-size-08x34-8x34-0002.i420
+b2ee07a6656af583f19593229fa11848 vp90-2-02-size-08x34-8x34-0003.i420
+74e3b5ab4c798a0afe745694e871bbd5 vp90-2-02-size-08x34-8x34-0004.i420
+35f1c30d0f8678f319a392a6c53b5989 vp90-2-02-size-08x34-8x34-0005.i420
+07e2b4c0b92a394bfb11124fe80476f0 vp90-2-02-size-08x34-8x34-0006.i420
+7864bd20dfc5280e5f027d67ea22bf30 vp90-2-02-size-08x34-8x34-0007.i420
+10a2925a7b91dfa9b82de76069388fd4 vp90-2-02-size-08x34-8x34-0008.i420
+79cc7f7a149e8d6e04e065f75e63733c vp90-2-02-size-08x34-8x34-0009.i420
+6453d10d97532d9bb03f7c06cba9fca0 vp90-2-02-size-08x34-8x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x64.vp9
new file mode 100644
index 0000000..337dfb9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x64_vp9_md5
new file mode 100644
index 0000000..f66d0c7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x64_vp9_md5
@@ -0,0 +1,10 @@
+764bd02b781a38c621a109c12f3d9393 vp90-2-02-size-08x64-8x64-0001.i420
+79496bd2b9212026af816b3b7a0587d5 vp90-2-02-size-08x64-8x64-0002.i420
+2a3afd47ba3d075033fd94d5c3746c45 vp90-2-02-size-08x64-8x64-0003.i420
+fca00cad8d37a6646337baebadd0ca31 vp90-2-02-size-08x64-8x64-0004.i420
+aca376fb3f8a5ef670ecc2430037262a vp90-2-02-size-08x64-8x64-0005.i420
+7e6c8d96d1e24855c3e380f1bf2ce02c vp90-2-02-size-08x64-8x64-0006.i420
+09e051241972969d439f27f324d78490 vp90-2-02-size-08x64-8x64-0007.i420
+2566b2a425caaba41305bf04ff10ea01 vp90-2-02-size-08x64-8x64-0008.i420
+db3995bedee42ada1b4ee63c339daf1b vp90-2-02-size-08x64-8x64-0009.i420
+b00b8f1bf4fd907f0487738f5b5442c6 vp90-2-02-size-08x64-8x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_08x66.vp9
new file mode 100644
index 0000000..46febdd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_08x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_08x66_vp9_md5
new file mode 100644
index 0000000..0c4649c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_08x66_vp9_md5
@@ -0,0 +1,10 @@
+df20e8df89449fe50bb610e95a449a95 vp90-2-02-size-08x66-8x66-0001.i420
+18f1a66d463274d1b0489f3a50e86857 vp90-2-02-size-08x66-8x66-0002.i420
+b0cc102875a94c9a92e53826617adbe9 vp90-2-02-size-08x66-8x66-0003.i420
+dfece7c17b4b149283ef51bdc1bd440e vp90-2-02-size-08x66-8x66-0004.i420
+6e346884f67be259fcabe493109cb63c vp90-2-02-size-08x66-8x66-0005.i420
+6d282127311eb2d958377490d7cb77f0 vp90-2-02-size-08x66-8x66-0006.i420
+637ac8b14ca5ddbaf7b8910406c3cd08 vp90-2-02-size-08x66-8x66-0007.i420
+e7980f3fcb36969da0d218c4389fa9e8 vp90-2-02-size-08x66-8x66-0008.i420
+730a1c95b9fb165f6e1a2f33a0d25de0 vp90-2-02-size-08x66-8x66-0009.i420
+7bd8424d0783b1c8ad617e17408371bb vp90-2-02-size-08x66-8x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x08.vp9
new file mode 100644
index 0000000..a27acd8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x08_vp9_md5
new file mode 100644
index 0000000..2f8e4be
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x08_vp9_md5
@@ -0,0 +1,10 @@
+e1e66a88615da98523ef887f1463fc42 vp90-2-02-size-10x08-10x8-0001.i420
+549842fa98c8faf572882d38b0aae390 vp90-2-02-size-10x08-10x8-0002.i420
+17ee85785517705fdc78c6122a4b2548 vp90-2-02-size-10x08-10x8-0003.i420
+1143391d419dac30a6c11f366157c974 vp90-2-02-size-10x08-10x8-0004.i420
+b62d2a962c4c36809ef75a610106715c vp90-2-02-size-10x08-10x8-0005.i420
+e6f143ca33fbc0e776bb149950cdedff vp90-2-02-size-10x08-10x8-0006.i420
+01716a1077ec66df00474fd4510d2789 vp90-2-02-size-10x08-10x8-0007.i420
+8cb5b6a865fa2cbb15f0d7736fda88a6 vp90-2-02-size-10x08-10x8-0008.i420
+0fb9fd883e895a540fe1704dddbbab04 vp90-2-02-size-10x08-10x8-0009.i420
+150a3b99aa24ef102c92f87c8adb4386 vp90-2-02-size-10x08-10x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x10.vp9
new file mode 100644
index 0000000..de3d37c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x10_vp9_md5
new file mode 100644
index 0000000..13ae622
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x10_vp9_md5
@@ -0,0 +1,10 @@
+083d638f2e147295d817bb14fff5e4f4 vp90-2-02-size-10x10-10x10-0001.i420
+6dbdc445b6fd6bb99f2025cc2a40977e vp90-2-02-size-10x10-10x10-0002.i420
+41714089383b181d64fbfa7de5904608 vp90-2-02-size-10x10-10x10-0003.i420
+11fdb8465e1599f7a9227706646d2cba vp90-2-02-size-10x10-10x10-0004.i420
+907876b3342a10040db0851a936af4e3 vp90-2-02-size-10x10-10x10-0005.i420
+e7b18d47d06b25de205d873d3d941640 vp90-2-02-size-10x10-10x10-0006.i420
+523ce7413c8da7f6a657a9b661f36c44 vp90-2-02-size-10x10-10x10-0007.i420
+23caff863af875c66c903662a3e1e6a1 vp90-2-02-size-10x10-10x10-0008.i420
+ed4cc5557203e5b7a119112ee9ceb00b vp90-2-02-size-10x10-10x10-0009.i420
+4bb78a996be3188888d1c60e11a08e1b vp90-2-02-size-10x10-10x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x16.vp9
new file mode 100644
index 0000000..843a547
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x16_vp9_md5
new file mode 100644
index 0000000..b614000
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x16_vp9_md5
@@ -0,0 +1,10 @@
+fab07d6209d2413e0a434e1aaaa12154 vp90-2-02-size-10x16-10x16-0001.i420
+f9ffffdb96f98527ba2e553d1265edbb vp90-2-02-size-10x16-10x16-0002.i420
+56a992264cf7da2b23dd97435e9d0365 vp90-2-02-size-10x16-10x16-0003.i420
+b1db980423d8004bd45a789b02b92a65 vp90-2-02-size-10x16-10x16-0004.i420
+b29496aedc7026566367b634f55ebb28 vp90-2-02-size-10x16-10x16-0005.i420
+2bc9def672da4a2fc17cbd669e2b8081 vp90-2-02-size-10x16-10x16-0006.i420
+8c54721514cdf577a52a8668b9135f13 vp90-2-02-size-10x16-10x16-0007.i420
+2efab81d5e039d82b3bc7b0303b022c4 vp90-2-02-size-10x16-10x16-0008.i420
+bd0f42b91b5d126fd0baec765b1096ad vp90-2-02-size-10x16-10x16-0009.i420
+c6bfea2735a629167bc6a7a7c76eb7f3 vp90-2-02-size-10x16-10x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x18.vp9
new file mode 100644
index 0000000..bd9c902
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x18_vp9_md5
new file mode 100644
index 0000000..0639abf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x18_vp9_md5
@@ -0,0 +1,10 @@
+0e9182e214aae732d94d007e5fe44888 vp90-2-02-size-10x18-10x18-0001.i420
+2630e2674b5611d68218fddac08815e2 vp90-2-02-size-10x18-10x18-0002.i420
+d5cdd7d6a3de17939f60bb60ef6877da vp90-2-02-size-10x18-10x18-0003.i420
+29d1961096061029e78963fa82581eca vp90-2-02-size-10x18-10x18-0004.i420
+5c2629f8aa59757f6b4aafa9f6cbcba1 vp90-2-02-size-10x18-10x18-0005.i420
+1f1a8b61e4fbd6222ddf42e9d0a07032 vp90-2-02-size-10x18-10x18-0006.i420
+cfb9771190ac2d0129907102d6abb63f vp90-2-02-size-10x18-10x18-0007.i420
+cd98dd856ba573a26a943cbe53221f26 vp90-2-02-size-10x18-10x18-0008.i420
+ca13c161f067c4a4ce22bd58a2aca55b vp90-2-02-size-10x18-10x18-0009.i420
+de4bd1a474a76a35b796a5fc45b4f893 vp90-2-02-size-10x18-10x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x32.vp9
new file mode 100644
index 0000000..4fa4f8b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x32_vp9_md5
new file mode 100644
index 0000000..aca6be0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x32_vp9_md5
@@ -0,0 +1,10 @@
+622e6407a051ea08706394d03330ffbf vp90-2-02-size-10x32-10x32-0001.i420
+1841a0daf7c3ef7be94e01fdb1d3968a vp90-2-02-size-10x32-10x32-0002.i420
+37790e6cb2415f7add0ac5d3ab354755 vp90-2-02-size-10x32-10x32-0003.i420
+91485880e17c292096a7335566d3648f vp90-2-02-size-10x32-10x32-0004.i420
+eb6f74983d5fd13d6bd90afbce8836e1 vp90-2-02-size-10x32-10x32-0005.i420
+0069ab5ff7f0d4d601f7d0f9b7a08338 vp90-2-02-size-10x32-10x32-0006.i420
+dbf04254765f7497070387e8c34895c6 vp90-2-02-size-10x32-10x32-0007.i420
+410a9b2d9855b2c29618070994adae96 vp90-2-02-size-10x32-10x32-0008.i420
+7e7f34effd90209f29f1b9ae01488b3b vp90-2-02-size-10x32-10x32-0009.i420
+471530f74082c01c9b0f1fcf3d240d77 vp90-2-02-size-10x32-10x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x34.vp9
new file mode 100644
index 0000000..e039c58
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x34_vp9_md5
new file mode 100644
index 0000000..1bd82bf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x34_vp9_md5
@@ -0,0 +1,10 @@
+bfeeaf51f972fd0dfe9ee757083cbb54 vp90-2-02-size-10x34-10x34-0001.i420
+10cd4ed6d762004846412d9cd0caa407 vp90-2-02-size-10x34-10x34-0002.i420
+04cca4008d656ed180de88dd2ddb4f21 vp90-2-02-size-10x34-10x34-0003.i420
+ec777e377836895748c06849fa35ed2d vp90-2-02-size-10x34-10x34-0004.i420
+b55633d0f9239dff3e45a4abce4a35a7 vp90-2-02-size-10x34-10x34-0005.i420
+063c3ab4b4c599942c3a8a5b7bfe5029 vp90-2-02-size-10x34-10x34-0006.i420
+07b920169d32b5fc51d5b9ae16fef5bf vp90-2-02-size-10x34-10x34-0007.i420
+8d49e727db9d3072b5ab7bab2133d9be vp90-2-02-size-10x34-10x34-0008.i420
+17441437203447e946a57d2f96966332 vp90-2-02-size-10x34-10x34-0009.i420
+5d3f14af0e5cd81d0c7d2059f13efa5a vp90-2-02-size-10x34-10x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x64.vp9
new file mode 100644
index 0000000..33817f0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x64_vp9_md5
new file mode 100644
index 0000000..26da4b6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x64_vp9_md5
@@ -0,0 +1,10 @@
+835254d0eecb17bed1f2b0f3a1638165 vp90-2-02-size-10x64-10x64-0001.i420
+c0c95ce9890eab339a0e0f8b26cb095c vp90-2-02-size-10x64-10x64-0002.i420
+f0337d645ade07cb716952b0d19352e8 vp90-2-02-size-10x64-10x64-0003.i420
+7e3deb21cb3f0ead90c8af94464cde14 vp90-2-02-size-10x64-10x64-0004.i420
+c6b1ca6cfce358c411c0637c581157c8 vp90-2-02-size-10x64-10x64-0005.i420
+10fce3f11f1ce90286ff4d74fe44fcfd vp90-2-02-size-10x64-10x64-0006.i420
+ee0565a1f121bc905a35550619127a50 vp90-2-02-size-10x64-10x64-0007.i420
+0624b601d379616eb792c94be60b6c91 vp90-2-02-size-10x64-10x64-0008.i420
+a1bb79cdf347548f1103f580f2b6930f vp90-2-02-size-10x64-10x64-0009.i420
+40e96e16c7e065aa7932e5aa57f32398 vp90-2-02-size-10x64-10x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_10x66.vp9
new file mode 100644
index 0000000..c0ffdc8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_10x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_10x66_vp9_md5
new file mode 100644
index 0000000..40a8a9a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_10x66_vp9_md5
@@ -0,0 +1,10 @@
+1bd8b2d3bf679c4b925780bf82e12fae vp90-2-02-size-10x66-10x66-0001.i420
+a0254b4cd4928fe1080cd6f8828288a9 vp90-2-02-size-10x66-10x66-0002.i420
+e416e99644cca481dc2806708d716ecb vp90-2-02-size-10x66-10x66-0003.i420
+b1ed3203ffc77ed814f1cda7bfe721d2 vp90-2-02-size-10x66-10x66-0004.i420
+0ff7b9d84765f7b0b0650775ba72b334 vp90-2-02-size-10x66-10x66-0005.i420
+8b6cd91e035bad19b46b132bd411231d vp90-2-02-size-10x66-10x66-0006.i420
+c714759a9a64402043ad00e5677c954c vp90-2-02-size-10x66-10x66-0007.i420
+8e4738010b724ce66bcd0a5d5afcfbc1 vp90-2-02-size-10x66-10x66-0008.i420
+998a7aab8ed94f4b69bed39fb487f8d5 vp90-2-02-size-10x66-10x66-0009.i420
+9964683a15a65c032631a4f608e6009b vp90-2-02-size-10x66-10x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_130x132.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_130x132.vp9
new file mode 100644
index 0000000..e14d5cc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_130x132.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_130x132_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_130x132_vp9_md5
new file mode 100644
index 0000000..451d950
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_130x132_vp9_md5
@@ -0,0 +1,10 @@
+8faddcc51f9bff5759dc15c7e6f5ce3f vp90_2_02_size_130x132.webm-130x132-0001.i420
+74fe93bd53a03c466da40d67431b6d41 vp90_2_02_size_130x132.webm-130x132-0002.i420
+3a40cd8fdab88af3d15b5d4af7d62245 vp90_2_02_size_130x132.webm-130x132-0003.i420
+5c232e8e11f4254f9bf437dcf91418b9 vp90_2_02_size_130x132.webm-130x132-0004.i420
+eb7f2d1700705697d05e322abe12d732 vp90_2_02_size_130x132.webm-130x132-0005.i420
+f3accfe25de02102fd996622f9b43499 vp90_2_02_size_130x132.webm-130x132-0006.i420
+270a3780fc7b84afbe8a340bc2e61871 vp90_2_02_size_130x132.webm-130x132-0007.i420
+c169f3a5d566a1a4afde6c309f1e4644 vp90_2_02_size_130x132.webm-130x132-0008.i420
+48b6fefacb63f286096fb0b65f8bc7c4 vp90_2_02_size_130x132.webm-130x132-0009.i420
+fcc24b1b542545bab9e45b9d79f6b41f vp90_2_02_size_130x132.webm-130x132-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_132x130.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_132x130.vp9
new file mode 100644
index 0000000..5282d3d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_132x130.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_132x130_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_132x130_vp9_md5
new file mode 100644
index 0000000..415deb4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_132x130_vp9_md5
@@ -0,0 +1,10 @@
+d75a9541df281c3fb1cd24f8be0788b3 vp90_2_02_size_132x130.webm-132x130-0001.i420
+a060549076fbf8856925c7f4a0e007b3 vp90_2_02_size_132x130.webm-132x130-0002.i420
+73ecf525a1a395deed6a7256e2c501d0 vp90_2_02_size_132x130.webm-132x130-0003.i420
+ec636e97f829b3457b7adda98c1c3580 vp90_2_02_size_132x130.webm-132x130-0004.i420
+f56f3f415b6b5d12fb5824aa82365cb3 vp90_2_02_size_132x130.webm-132x130-0005.i420
+376735c39fea4c2f48b8d2d260f9b73e vp90_2_02_size_132x130.webm-132x130-0006.i420
+c616f543aaa73342b561f08ec24d9792 vp90_2_02_size_132x130.webm-132x130-0007.i420
+b86a6ecf6e5df70b9505861bcc8ac95e vp90_2_02_size_132x130.webm-132x130-0008.i420
+1d9bc98446d2068fe37abc60abce0d28 vp90_2_02_size_132x130.webm-132x130-0009.i420
+febd071a35d2407e29f72c46f14f4667 vp90_2_02_size_132x130.webm-132x130-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_132x132.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_132x132.vp9
new file mode 100644
index 0000000..7c36464
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_132x132.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_132x132_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_132x132_vp9_md5
new file mode 100644
index 0000000..cb04a76
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_132x132_vp9_md5
@@ -0,0 +1,10 @@
+5dc0ef6d1452bf220dfe752b9c0a6081 vp90_2_02_size_132x132.webm-132x132-0001.i420
+cdec24d8945577908cd05a3254edc1ea vp90_2_02_size_132x132.webm-132x132-0002.i420
+ce4978e6ab380156c33943b225145af2 vp90_2_02_size_132x132.webm-132x132-0003.i420
+516c9256ab785f04f41fa7b44ac89e6d vp90_2_02_size_132x132.webm-132x132-0004.i420
+16071c396c07639360260d6544bbc198 vp90_2_02_size_132x132.webm-132x132-0005.i420
+8876317adaf2ee98682b0dbfa50b9cbc vp90_2_02_size_132x132.webm-132x132-0006.i420
+a30299b275dfd0a08191f6a9f6633138 vp90_2_02_size_132x132.webm-132x132-0007.i420
+49b3e47e41d00cc283d3906bde82abc7 vp90_2_02_size_132x132.webm-132x132-0008.i420
+a922b8d8d9883b5fd05358724a1a84c2 vp90_2_02_size_132x132.webm-132x132-0009.i420
+1bc5c3b99f979087cd6065a9894b0d6d vp90_2_02_size_132x132.webm-132x132-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x08.vp9
new file mode 100644
index 0000000..4de0d73
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x08_vp9_md5
new file mode 100644
index 0000000..3e3e92a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x08_vp9_md5
@@ -0,0 +1,10 @@
+68dccd167f9aa18df0840ebb8715eb68 vp90-2-02-size-16x08-16x8-0001.i420
+65c90bb99fdbee7abf21031d34cb18dc vp90-2-02-size-16x08-16x8-0002.i420
+9ef1feb2dcbd4d73f3ee84e9e1cd2668 vp90-2-02-size-16x08-16x8-0003.i420
+b6281f7c88e9aa132d3902046f8cde5a vp90-2-02-size-16x08-16x8-0004.i420
+4b439b716a294bddf9f56a229705907b vp90-2-02-size-16x08-16x8-0005.i420
+d42c0a6f0d24522c90bc2233bc1df2c7 vp90-2-02-size-16x08-16x8-0006.i420
+74b763a5a12c4c4a581efb1818a92970 vp90-2-02-size-16x08-16x8-0007.i420
+0c3a0916ddfda5abdd3ac382f036e71f vp90-2-02-size-16x08-16x8-0008.i420
+26ff590e8ae726f70e8b36f5eaee7a19 vp90-2-02-size-16x08-16x8-0009.i420
+30fa5810995d7132387ea585c4a1cc3a vp90-2-02-size-16x08-16x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x10.vp9
new file mode 100644
index 0000000..541937a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x10_vp9_md5
new file mode 100644
index 0000000..9e00483
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x10_vp9_md5
@@ -0,0 +1,10 @@
+fb3cad61d7d9eb511758dbf87dd8abe1 vp90-2-02-size-16x10-16x10-0001.i420
+4fbc1aa5559c8db2930803893bd6ba75 vp90-2-02-size-16x10-16x10-0002.i420
+2d8e2ee04dcc6097ca9e3f27070cdcc8 vp90-2-02-size-16x10-16x10-0003.i420
+05d419f1322855ba3620665b68ce9910 vp90-2-02-size-16x10-16x10-0004.i420
+b004f8d88cb2c94f4e9a13cfa5bd480a vp90-2-02-size-16x10-16x10-0005.i420
+9d9dec90e2213c0411939131aa9adf7f vp90-2-02-size-16x10-16x10-0006.i420
+a00874356ff1b1e9da1a400424661f8d vp90-2-02-size-16x10-16x10-0007.i420
+fda587eb6323cd98c773f05905ac1794 vp90-2-02-size-16x10-16x10-0008.i420
+781c63d221a04d8130806c799d16753a vp90-2-02-size-16x10-16x10-0009.i420
+f346e311829f3789dc5a94da48ada5f4 vp90-2-02-size-16x10-16x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x16.vp9
new file mode 100644
index 0000000..4b7f230
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x16_vp9_md5
new file mode 100644
index 0000000..11de2b8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x16_vp9_md5
@@ -0,0 +1,10 @@
+b5c9daafa548e54a8e33e9881fda33f4 vp90-2-02-size-16x16-16x16-0001.i420
+1193acd7ea4b7aac968e35ef83c64378 vp90-2-02-size-16x16-16x16-0002.i420
+cd0e42c0b5a8b3be6f0e1d224062bf99 vp90-2-02-size-16x16-16x16-0003.i420
+ed79c71d17f68f86cbfa75ea2bfe97f3 vp90-2-02-size-16x16-16x16-0004.i420
+1502a859c7e07b31faad5b80e3e27cf7 vp90-2-02-size-16x16-16x16-0005.i420
+df3f093da914ea947db93c3baa188ecb vp90-2-02-size-16x16-16x16-0006.i420
+480f86eb183b99277c1b38fdaafe2970 vp90-2-02-size-16x16-16x16-0007.i420
+023e0114282e04963f0f52e00e65ac61 vp90-2-02-size-16x16-16x16-0008.i420
+e67f29cf0acc7f9b553458e1e5c59ebf vp90-2-02-size-16x16-16x16-0009.i420
+a779a14ba718f0c1df8a7edc9467d12e vp90-2-02-size-16x16-16x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x18.vp9
new file mode 100644
index 0000000..de0bddc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x18_vp9_md5
new file mode 100644
index 0000000..7dcc81a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x18_vp9_md5
@@ -0,0 +1,10 @@
+5156b11cd9995d0c1638c9b0d2b0786c vp90-2-02-size-16x18-16x18-0001.i420
+ef78557f93fb3ea770c7d49ab60edf21 vp90-2-02-size-16x18-16x18-0002.i420
+f31fb9bb14566e4538a45ac7bf398b2a vp90-2-02-size-16x18-16x18-0003.i420
+97633875537f76ade183e975fa91b0fb vp90-2-02-size-16x18-16x18-0004.i420
+602cf54f9af852175173c21abd63796f vp90-2-02-size-16x18-16x18-0005.i420
+0b3741a6842cb65d6d21eda891882033 vp90-2-02-size-16x18-16x18-0006.i420
+44240a27a6b6d36c9661d499fb965f87 vp90-2-02-size-16x18-16x18-0007.i420
+9050f263f9a4767f9323ec8aa42cf7e6 vp90-2-02-size-16x18-16x18-0008.i420
+57fa3a8494375f588a95376bc0c3cb28 vp90-2-02-size-16x18-16x18-0009.i420
+084595f2a65aa10e7d3845044a0e7213 vp90-2-02-size-16x18-16x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x32.vp9
new file mode 100644
index 0000000..35371d5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x32_vp9_md5
new file mode 100644
index 0000000..f7b1555
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x32_vp9_md5
@@ -0,0 +1,10 @@
+c73d611490a5ddec6c690589deaf5e86 vp90-2-02-size-16x32-16x32-0001.i420
+5d8eaeb222aa64abda59ce7b09b2f6d9 vp90-2-02-size-16x32-16x32-0002.i420
+34321856b8dd5bbb9b63db04d3532289 vp90-2-02-size-16x32-16x32-0003.i420
+947337d2fec8a09242f60e31e99f4065 vp90-2-02-size-16x32-16x32-0004.i420
+bb7d92f6fc055f0cf0e97bd2be56cc9e vp90-2-02-size-16x32-16x32-0005.i420
+5d343c82bcdd0e9d08581043cddfd0ca vp90-2-02-size-16x32-16x32-0006.i420
+612ded93207712e4916d584cc4a7b87c vp90-2-02-size-16x32-16x32-0007.i420
+6ba5e0d19893e1b96f5ca86e0bfd7e18 vp90-2-02-size-16x32-16x32-0008.i420
+336572e1dcb110b1eb87bea81e0752f4 vp90-2-02-size-16x32-16x32-0009.i420
+705f73d0a39afce59ea571e68bfe25df vp90-2-02-size-16x32-16x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x34.vp9
new file mode 100644
index 0000000..a9c1024
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x34_vp9_md5
new file mode 100644
index 0000000..169e06c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x34_vp9_md5
@@ -0,0 +1,10 @@
+b8bf711d9a1ce49180ed56407c8a4b0a vp90-2-02-size-16x34-16x34-0001.i420
+0457929b06ce46aec63d66bd38586e3f vp90-2-02-size-16x34-16x34-0002.i420
+3b5f417ee5a936797a6f0d138b8ed73b vp90-2-02-size-16x34-16x34-0003.i420
+5d1a42aeecfd5c8513cb2df94c206c8b vp90-2-02-size-16x34-16x34-0004.i420
+a0ab2dddbc810a1667d779f6ed69d010 vp90-2-02-size-16x34-16x34-0005.i420
+b150cd7c4ec83e6f9d948e99d7465350 vp90-2-02-size-16x34-16x34-0006.i420
+ea39622ad21312bd8bcecdaf09aa18fb vp90-2-02-size-16x34-16x34-0007.i420
+467a42e1226a01c8ba244f312f588bab vp90-2-02-size-16x34-16x34-0008.i420
+f2311e15228ffc7fd377b89c203d0fbf vp90-2-02-size-16x34-16x34-0009.i420
+5df58b3ac0a7856796a46f27be7dcf4c vp90-2-02-size-16x34-16x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x64.vp9
new file mode 100644
index 0000000..4f9d19c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x64_vp9_md5
new file mode 100644
index 0000000..5b98188
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x64_vp9_md5
@@ -0,0 +1,10 @@
+925fdc485f3baa1ed145ae391519d7fd vp90-2-02-size-16x64-16x64-0001.i420
+d37af656da2d7a727c8451773495d5ed vp90-2-02-size-16x64-16x64-0002.i420
+8a0f207a99e46f3d3b2aaa3f1b061981 vp90-2-02-size-16x64-16x64-0003.i420
+a3914c7b739d3af2641fd6aae35428ef vp90-2-02-size-16x64-16x64-0004.i420
+0ba3b49970d7b029f2dfa991fdfc6e61 vp90-2-02-size-16x64-16x64-0005.i420
+55838d1d787dc5a4fa4da2994f04587f vp90-2-02-size-16x64-16x64-0006.i420
+c089f7ba2b2983df2a4dc2e07798af31 vp90-2-02-size-16x64-16x64-0007.i420
+c23dcb3b109543a61ccfa404a726caae vp90-2-02-size-16x64-16x64-0008.i420
+01aaf09960f5ca599ca32768f017d0c9 vp90-2-02-size-16x64-16x64-0009.i420
+79fe955692ecba8bbb00b20a42ca8104 vp90-2-02-size-16x64-16x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_16x66.vp9
new file mode 100644
index 0000000..4499869
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_16x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_16x66_vp9_md5
new file mode 100644
index 0000000..34f48af
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_16x66_vp9_md5
@@ -0,0 +1,10 @@
+c7b0d91f362dff0a581434af6e902d43 vp90-2-02-size-16x66-16x66-0001.i420
+d8b016ef59c6bc193b29d1c714f342c1 vp90-2-02-size-16x66-16x66-0002.i420
+c520bd8d4b81aafc7687befff66c7396 vp90-2-02-size-16x66-16x66-0003.i420
+92e81bbd3af675c9cdb1cb00d03dabe1 vp90-2-02-size-16x66-16x66-0004.i420
+a271db3defe5daa6d9e0a73a580f4f88 vp90-2-02-size-16x66-16x66-0005.i420
+4077e857321e241bb98dfd89c0aca46f vp90-2-02-size-16x66-16x66-0006.i420
+0466e1453a94baf876e9f64b60235300 vp90-2-02-size-16x66-16x66-0007.i420
+9d2cb9c7b180d44841e0e4d8a595d912 vp90-2-02-size-16x66-16x66-0008.i420
+500f443eeb0ecef47c34d1e91f0df6ce vp90-2-02-size-16x66-16x66-0009.i420
+83354487982915c33b1c6243d80adaeb vp90-2-02-size-16x66-16x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_178x180.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_178x180.vp9
new file mode 100644
index 0000000..c7f72dc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_178x180.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_178x180_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_178x180_vp9_md5
new file mode 100644
index 0000000..8af554c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_178x180_vp9_md5
@@ -0,0 +1,10 @@
+ca7515c880d0a8230432e77abf3e3d33 vp90_2_02_size_178x180.webm-178x180-0001.i420
+7612d57deeb9d947529f73dd1b64a08d vp90_2_02_size_178x180.webm-178x180-0002.i420
+a230690af19b975ffaca630e84e648fe vp90_2_02_size_178x180.webm-178x180-0003.i420
+c6f829cb3462fcc0f7259819797c3283 vp90_2_02_size_178x180.webm-178x180-0004.i420
+3d13df53df5abb8d7602ffb0a3c89bb6 vp90_2_02_size_178x180.webm-178x180-0005.i420
+08ed7474c5630c1d7de6e32906f8b62f vp90_2_02_size_178x180.webm-178x180-0006.i420
+d09e4324a86be4e4141fcd72b855744b vp90_2_02_size_178x180.webm-178x180-0007.i420
+2934746d377ee23fd3eaeea27d049210 vp90_2_02_size_178x180.webm-178x180-0008.i420
+9cbad3dfc8a5665f57f483fede1ac91c vp90_2_02_size_178x180.webm-178x180-0009.i420
+9c2dc6879c5778f293db30eac2fe7103 vp90_2_02_size_178x180.webm-178x180-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_180x178.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_180x178.vp9
new file mode 100644
index 0000000..340be2b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_180x178.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_180x178_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_180x178_vp9_md5
new file mode 100644
index 0000000..dd72479
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_180x178_vp9_md5
@@ -0,0 +1,10 @@
+461aa52a5658cbb30320be36bf42867d vp90_2_02_size_180x178.webm-180x178-0001.i420
+a6c5fb033c04b5bdbe47a07a2ea8a001 vp90_2_02_size_180x178.webm-180x178-0002.i420
+de1d2789826b143aaae0b7c337332a69 vp90_2_02_size_180x178.webm-180x178-0003.i420
+aaf60e6369a72ea8fe47b3767b6b4aef vp90_2_02_size_180x178.webm-180x178-0004.i420
+40c6bfaf1f4bcd39d6c6cf588ea445cb vp90_2_02_size_180x178.webm-180x178-0005.i420
+3bfe6508595fb0c000c196cb6387531b vp90_2_02_size_180x178.webm-180x178-0006.i420
+b70dcaad6d9dd7fe378b323460c3a243 vp90_2_02_size_180x178.webm-180x178-0007.i420
+201fce98c70f2623196a44e40a4850ac vp90_2_02_size_180x178.webm-180x178-0008.i420
+aba16ce70b06355a025d003d6974790b vp90_2_02_size_180x178.webm-180x178-0009.i420
+39220f4dd594972d258788528d19460c vp90_2_02_size_180x178.webm-180x178-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_180x180.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_180x180.vp9
new file mode 100644
index 0000000..c01cc6f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_180x180.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_180x180_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_180x180_vp9_md5
new file mode 100644
index 0000000..f257f21
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_180x180_vp9_md5
@@ -0,0 +1,10 @@
+325a336bcaf9987ab1ad3f6a7328d2be vp90_2_02_size_180x180.webm-180x180-0001.i420
+e7d73157a4861d98318240b60d157f55 vp90_2_02_size_180x180.webm-180x180-0002.i420
+1db60eb53a9756c751325942a021b36e vp90_2_02_size_180x180.webm-180x180-0003.i420
+c0adb82dc19f4cabcebd18f0d7712ee5 vp90_2_02_size_180x180.webm-180x180-0004.i420
+35b768881097c1e6b99814e4fbf905d1 vp90_2_02_size_180x180.webm-180x180-0005.i420
+c3af16f1334c6baa0a51086f57c7cfd5 vp90_2_02_size_180x180.webm-180x180-0006.i420
+d30718f4a93162e7752e5177096718ee vp90_2_02_size_180x180.webm-180x180-0007.i420
+b73f17d3affa5a9f69273579c09f4566 vp90_2_02_size_180x180.webm-180x180-0008.i420
+f596f4234d2486985a2d94ce73bd72ad vp90_2_02_size_180x180.webm-180x180-0009.i420
+aab77693ee7b744c81a0b913f5318ac2 vp90_2_02_size_180x180.webm-180x180-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x08.vp9
new file mode 100644
index 0000000..c1b063e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x08_vp9_md5
new file mode 100644
index 0000000..19f6cbe
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x08_vp9_md5
@@ -0,0 +1,10 @@
+3219af4ef540636b0f67a989e9966059 vp90-2-02-size-18x08-18x8-0001.i420
+1a3655c2cfd2ee332bc89da5b3faf778 vp90-2-02-size-18x08-18x8-0002.i420
+d638d5b361a6d81440e26993ed86c97d vp90-2-02-size-18x08-18x8-0003.i420
+d9bc2e7cffd66db4ba9dcbce99448d4d vp90-2-02-size-18x08-18x8-0004.i420
+399f962e0a0573915bc4da4a9f1effcf vp90-2-02-size-18x08-18x8-0005.i420
+69d917e19b903e4f07f848e9e557bbe7 vp90-2-02-size-18x08-18x8-0006.i420
+d6311488a58acf6eb0cc45bc4fe3c2da vp90-2-02-size-18x08-18x8-0007.i420
+0ce360a84d5755307f98d65c83f190e1 vp90-2-02-size-18x08-18x8-0008.i420
+2554828e6dbf94424ccac30fb153872e vp90-2-02-size-18x08-18x8-0009.i420
+598a55f9735e85b8d45105dd6be7f97b vp90-2-02-size-18x08-18x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x10.vp9
new file mode 100644
index 0000000..5b1d1f4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x10_vp9_md5
new file mode 100644
index 0000000..f79825a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x10_vp9_md5
@@ -0,0 +1,10 @@
+bf574489e9360b6475aa012c747e7924 vp90-2-02-size-18x10-18x10-0001.i420
+851100301c2937312a6fd32f5aab5a09 vp90-2-02-size-18x10-18x10-0002.i420
+0f7c1209e44ea7cd4df12d82f9224684 vp90-2-02-size-18x10-18x10-0003.i420
+28d121f9c40de5280435bfdeaec0c072 vp90-2-02-size-18x10-18x10-0004.i420
+bb00898d03ce4dff5f7bee719dd3f5b5 vp90-2-02-size-18x10-18x10-0005.i420
+a098cc66bc25b81f84b0e930b0915cdb vp90-2-02-size-18x10-18x10-0006.i420
+81e25f19bfcbfce17bd7138eedae04ee vp90-2-02-size-18x10-18x10-0007.i420
+69c36c5ce555a461f16a1733450f7258 vp90-2-02-size-18x10-18x10-0008.i420
+c95236d9e7c624bb664310bd9ef47fb4 vp90-2-02-size-18x10-18x10-0009.i420
+7ab0942e686939951037314e9402d2c1 vp90-2-02-size-18x10-18x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x16.vp9
new file mode 100644
index 0000000..f27acd1
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x16_vp9_md5
new file mode 100644
index 0000000..aeafea2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x16_vp9_md5
@@ -0,0 +1,10 @@
+9535aaa2ea26fbdc16e7fe9cba3fc9b4 vp90-2-02-size-18x16-18x16-0001.i420
+7f6e7ca33c0b27ff052dc2ab6721e37d vp90-2-02-size-18x16-18x16-0002.i420
+d37e3f169457a9c7f2a197353e39d3d6 vp90-2-02-size-18x16-18x16-0003.i420
+f26d7d81dd81d051680ea2485e812705 vp90-2-02-size-18x16-18x16-0004.i420
+704b01955ced6d101b9e9315d3327f28 vp90-2-02-size-18x16-18x16-0005.i420
+30d46d6a0f6be383dede451cacf465f4 vp90-2-02-size-18x16-18x16-0006.i420
+83c7ed04f0af61ec665041967cbce05d vp90-2-02-size-18x16-18x16-0007.i420
+152daf37dd37607886c50dd4c7796357 vp90-2-02-size-18x16-18x16-0008.i420
+609d807351ba74b1c432e3d0516add91 vp90-2-02-size-18x16-18x16-0009.i420
+67953f0c735984232cb6782217cdcdf6 vp90-2-02-size-18x16-18x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x18.vp9
new file mode 100644
index 0000000..35ec6a7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x18_vp9_md5
new file mode 100644
index 0000000..9600c40e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x18_vp9_md5
@@ -0,0 +1,10 @@
+83790b0e7004d8d89b7134ee1a88d885 vp90-2-02-size-18x18-18x18-0001.i420
+0baf0bf556ae56d2f4b04567e6ac7ed9 vp90-2-02-size-18x18-18x18-0002.i420
+c648854a4d49f7e407a2450cf4ba292a vp90-2-02-size-18x18-18x18-0003.i420
+510c3aca23339841ffc72ed5c75d184e vp90-2-02-size-18x18-18x18-0004.i420
+1c1f3116ec4d4ee1ad790652e49233ad vp90-2-02-size-18x18-18x18-0005.i420
+f94891f4e16fd32d638a2c696f5922e6 vp90-2-02-size-18x18-18x18-0006.i420
+e164814c22e38cbe45312dfd48d987fc vp90-2-02-size-18x18-18x18-0007.i420
+f582515fcc6c4308ad931d2f6cf371a0 vp90-2-02-size-18x18-18x18-0008.i420
+0a446974bd227ee34a1621a2b7852abb vp90-2-02-size-18x18-18x18-0009.i420
+beca28bdae8d1fe20036b3646f3109cd vp90-2-02-size-18x18-18x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x32.vp9
new file mode 100644
index 0000000..f288c06
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x32_vp9_md5
new file mode 100644
index 0000000..697fa7d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x32_vp9_md5
@@ -0,0 +1,10 @@
+62eabc8819ded6ddba2c3a5029497cf0 vp90-2-02-size-18x32-18x32-0001.i420
+b760182fddf8bc05f149e80bbcb2c281 vp90-2-02-size-18x32-18x32-0002.i420
+0c44be0472ebd2653ce9fb174c6180ab vp90-2-02-size-18x32-18x32-0003.i420
+bbb033c3bfeeb6f59cb43013597b9d92 vp90-2-02-size-18x32-18x32-0004.i420
+a769975cdbc6529525f7cac8a0d9299a vp90-2-02-size-18x32-18x32-0005.i420
+15b02059bbced62f19c0626efea1ecb9 vp90-2-02-size-18x32-18x32-0006.i420
+47f4b50322ed31649bdcfffb05c70fa2 vp90-2-02-size-18x32-18x32-0007.i420
+8649cdd0a958047839f5b6e7bbf6f288 vp90-2-02-size-18x32-18x32-0008.i420
+2c766e3fd3882a9a5aff52ffe9d1d341 vp90-2-02-size-18x32-18x32-0009.i420
+184a62b7332a1c24acbf03f670fb7ac1 vp90-2-02-size-18x32-18x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x34.vp9
new file mode 100644
index 0000000..6b8c072
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x34_vp9_md5
new file mode 100644
index 0000000..2b9926c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x34_vp9_md5
@@ -0,0 +1,10 @@
+612cc424eaae924cb25c7732c422f752 vp90-2-02-size-18x34-18x34-0001.i420
+010e8c2a814862529fcf8d7771ba2d7f vp90-2-02-size-18x34-18x34-0002.i420
+7d791b7a5916738998f77586339d5840 vp90-2-02-size-18x34-18x34-0003.i420
+aeada5f59f3dda9ab3e898f305428cb2 vp90-2-02-size-18x34-18x34-0004.i420
+06af894d38a1f0d3665c0081f5397ddf vp90-2-02-size-18x34-18x34-0005.i420
+24bf31323c568e652550e9d35de9c96c vp90-2-02-size-18x34-18x34-0006.i420
+a9681ec47d3e6a19321b9ea47221dc3f vp90-2-02-size-18x34-18x34-0007.i420
+73ae7268df79c4012952bd3e8011e894 vp90-2-02-size-18x34-18x34-0008.i420
+67aa4145398ca17036959251cb4ce17b vp90-2-02-size-18x34-18x34-0009.i420
+de247b80114c722da849f5aa23adbb38 vp90-2-02-size-18x34-18x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x64.vp9
new file mode 100644
index 0000000..da13d78
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x64_vp9_md5
new file mode 100644
index 0000000..0fbd0c0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x64_vp9_md5
@@ -0,0 +1,10 @@
+72c74de547d9ed1b17bc962dbd5e0bb1 vp90-2-02-size-18x64-18x64-0001.i420
+462849f9e2204738e9f08b40e682a6ae vp90-2-02-size-18x64-18x64-0002.i420
+f0ee17692fd816747b11d5737b511cda vp90-2-02-size-18x64-18x64-0003.i420
+0234d23406660ede76dd22b35a708390 vp90-2-02-size-18x64-18x64-0004.i420
+6544fdb9dc225d155820d3c7dfc909eb vp90-2-02-size-18x64-18x64-0005.i420
+1c073544794389596177512fb4dcffce vp90-2-02-size-18x64-18x64-0006.i420
+864709daac7b091d33afa2210c145084 vp90-2-02-size-18x64-18x64-0007.i420
+b049c4ac941743613ede9a41b16acde5 vp90-2-02-size-18x64-18x64-0008.i420
+ad0c4adb0efec03729a79f42eec66267 vp90-2-02-size-18x64-18x64-0009.i420
+146057d941f5a47eb8b2c9eefeaf3100 vp90-2-02-size-18x64-18x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_18x66.vp9
new file mode 100644
index 0000000..b1ffba7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_18x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_18x66_vp9_md5
new file mode 100644
index 0000000..46a7a3d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_18x66_vp9_md5
@@ -0,0 +1,10 @@
+c3fc4a1593b9cc2f3752106af8539386 vp90-2-02-size-18x66-18x66-0001.i420
+7f2ffe6bc1750f6749bb5ad12cbaf34b vp90-2-02-size-18x66-18x66-0002.i420
+2539b10a981d59ef54efd77cd7276aaa vp90-2-02-size-18x66-18x66-0003.i420
+0bff22b4dfb7485fbedd6ff5b99673d1 vp90-2-02-size-18x66-18x66-0004.i420
+6a2b38f4abee785260a61bc60f16e7fa vp90-2-02-size-18x66-18x66-0005.i420
+2fbb69b5519b51548bf1ee425ff79c55 vp90-2-02-size-18x66-18x66-0006.i420
+dbd267028be2256111b2411b91fcc117 vp90-2-02-size-18x66-18x66-0007.i420
+12b2f1003633c9e19cae3d0fda06102d vp90-2-02-size-18x66-18x66-0008.i420
+d419a756c492867523af5185fd57d989 vp90-2-02-size-18x66-18x66-0009.i420
+8a7d36760bf5db32baef349b97316b47 vp90-2-02-size-18x66-18x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x08.vp9
new file mode 100644
index 0000000..97e741c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x08_vp9_md5
new file mode 100644
index 0000000..b744f57
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x08_vp9_md5
@@ -0,0 +1,10 @@
+c7b30cde5664387b0f7a80d9b01e4fe2 vp90-2-02-size-32x08-32x8-0001.i420
+2228a2a4e54ab5145525e5803c314dcd vp90-2-02-size-32x08-32x8-0002.i420
+8c048469eba24f3163c36b7461b3b42a vp90-2-02-size-32x08-32x8-0003.i420
+f6b8e8e701dea09dcf1158e9a52921c6 vp90-2-02-size-32x08-32x8-0004.i420
+b3a5fde0daf2eef8fc08521f88f79692 vp90-2-02-size-32x08-32x8-0005.i420
+653ae11cc1380ae7f39b2e007f896d81 vp90-2-02-size-32x08-32x8-0006.i420
+6e66fe002a7dff95e13cc9d3d13d9686 vp90-2-02-size-32x08-32x8-0007.i420
+13308c917a1e22c2f702afc32b8a23c2 vp90-2-02-size-32x08-32x8-0008.i420
+4fee1e63f9452dc3f81c1d634bd7f41d vp90-2-02-size-32x08-32x8-0009.i420
+666b43ead5c7c99ae5b7637da5aa4d62 vp90-2-02-size-32x08-32x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x10.vp9
new file mode 100644
index 0000000..acfa19b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x10_vp9_md5
new file mode 100644
index 0000000..cb40846
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x10_vp9_md5
@@ -0,0 +1,10 @@
+7c5b5df373ebfd31d210ff910e02213b vp90-2-02-size-32x10-32x10-0001.i420
+c5b0a5e3eceb792b15818324a43aa2a8 vp90-2-02-size-32x10-32x10-0002.i420
+1d9c0eafd4638dfe4fe308174fde2faf vp90-2-02-size-32x10-32x10-0003.i420
+47301d12055944b35008028761cf5e7b vp90-2-02-size-32x10-32x10-0004.i420
+9586ac1087423dcd3b0ff96d43ae475e vp90-2-02-size-32x10-32x10-0005.i420
+26bfe1afea96c7ef2084fffd1fa99a33 vp90-2-02-size-32x10-32x10-0006.i420
+0995c8a1935266159a7ef3f95d7f4697 vp90-2-02-size-32x10-32x10-0007.i420
+8cfcc0ea67507ab7f3551d8ac50f93a5 vp90-2-02-size-32x10-32x10-0008.i420
+658cf3cb887b055d9de7d50db4eb78a9 vp90-2-02-size-32x10-32x10-0009.i420
+856bd5189688f7ccfe9995752bc0f1f6 vp90-2-02-size-32x10-32x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x16.vp9
new file mode 100644
index 0000000..dec3c01
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x16_vp9_md5
new file mode 100644
index 0000000..7609114
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x16_vp9_md5
@@ -0,0 +1,10 @@
+7c2818db2632e5c5beee17e7105d9209 vp90-2-02-size-32x16-32x16-0001.i420
+cead72bd22995e98b54a91c7b4a20975 vp90-2-02-size-32x16-32x16-0002.i420
+eb6baee5d65d778052c88ba5db2f9174 vp90-2-02-size-32x16-32x16-0003.i420
+1f5f38e89e985e9e4172446de05e91fd vp90-2-02-size-32x16-32x16-0004.i420
+57b57ffcb03627942fc5868324a10feb vp90-2-02-size-32x16-32x16-0005.i420
+4b4066a452d8e9cd687cd611f5d9cb88 vp90-2-02-size-32x16-32x16-0006.i420
+113e5069b2a4d2c2e802b72649eb435d vp90-2-02-size-32x16-32x16-0007.i420
+e176bb233f76f9fd4c55d62d53487b60 vp90-2-02-size-32x16-32x16-0008.i420
+f2ff3def712a846ea7b678bd9078e32b vp90-2-02-size-32x16-32x16-0009.i420
+21007ed1c727c5ccc5955188a2cec276 vp90-2-02-size-32x16-32x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x18.vp9
new file mode 100644
index 0000000..2062e61
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x18_vp9_md5
new file mode 100644
index 0000000..4bd047f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x18_vp9_md5
@@ -0,0 +1,10 @@
+9da5409d344e7b8380688569e54803a5 vp90-2-02-size-32x18-32x18-0001.i420
+9b51e14e2e624ee2b430e9eaf1a48798 vp90-2-02-size-32x18-32x18-0002.i420
+b8811779f363b9a595e3a92737771ea9 vp90-2-02-size-32x18-32x18-0003.i420
+e5a0c335e5e713a3e77fff0b65127fb9 vp90-2-02-size-32x18-32x18-0004.i420
+1bffa3283b463a356794c8f7a73f8c54 vp90-2-02-size-32x18-32x18-0005.i420
+97c13270621a583eb9e13c05f9d792f0 vp90-2-02-size-32x18-32x18-0006.i420
+a6f81a4dde1ffc352ebe9d8ab8782f35 vp90-2-02-size-32x18-32x18-0007.i420
+91a955a86ce9378ff3442794ce0934c6 vp90-2-02-size-32x18-32x18-0008.i420
+2e4f8938e9c88b328a258a0b99366ea6 vp90-2-02-size-32x18-32x18-0009.i420
+adbbbc192cf36e1fc7c308824765d482 vp90-2-02-size-32x18-32x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x32.vp9
new file mode 100644
index 0000000..fbfa4ab
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x32_vp9_md5
new file mode 100644
index 0000000..4e5b3c4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x32_vp9_md5
@@ -0,0 +1,10 @@
+117915db1856cee26f05a609c8c8de2e vp90-2-02-size-32x32-32x32-0001.i420
+943771a98b26b174e88ed1f4e872e504 vp90-2-02-size-32x32-32x32-0002.i420
+3e0d2585e1f1cb540998d107aca5c395 vp90-2-02-size-32x32-32x32-0003.i420
+e64a9e1e0232983a69ab48453025b23d vp90-2-02-size-32x32-32x32-0004.i420
+2c6ef6637fb7b9425f7d7ea28cd84087 vp90-2-02-size-32x32-32x32-0005.i420
+419a5a31a43955d408c13ee8a5ddce9c vp90-2-02-size-32x32-32x32-0006.i420
+2ab13e1c236553d42d59498ca350b190 vp90-2-02-size-32x32-32x32-0007.i420
+b8068beb037f3232d4da38fe33a8a885 vp90-2-02-size-32x32-32x32-0008.i420
+160df68b9e3f75e9b1f8ed7cce327bc2 vp90-2-02-size-32x32-32x32-0009.i420
+1ccafa8c7babdce0983aeb20d298b0ee vp90-2-02-size-32x32-32x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x34.vp9
new file mode 100644
index 0000000..7ea9965
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x34_vp9_md5
new file mode 100644
index 0000000..28b1e11
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x34_vp9_md5
@@ -0,0 +1,10 @@
+770582911fd0095ebbeae384e87665ac vp90-2-02-size-32x34-32x34-0001.i420
+f99d7e3131f04413cba2f9de6818976d vp90-2-02-size-32x34-32x34-0002.i420
+3bfbb8c9c48f24cd596973a6deb33a3f vp90-2-02-size-32x34-32x34-0003.i420
+0b8166afdd357f20c76f77d228bb7171 vp90-2-02-size-32x34-32x34-0004.i420
+3a3d7f2a03e19a82250d6ca0238f9791 vp90-2-02-size-32x34-32x34-0005.i420
+9b558f9b8744b016059f69f3fca90d2c vp90-2-02-size-32x34-32x34-0006.i420
+c857736342f1145d919cb77732120006 vp90-2-02-size-32x34-32x34-0007.i420
+11dc5dda4c883a3146db060dd50343d0 vp90-2-02-size-32x34-32x34-0008.i420
+7526a62ae87de174be86eac7bb36c7f3 vp90-2-02-size-32x34-32x34-0009.i420
+9ef38f47cfc461710ff0dd75690473c0 vp90-2-02-size-32x34-32x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x64.vp9
new file mode 100644
index 0000000..0bc9223
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x64_vp9_md5
new file mode 100644
index 0000000..d00ccc6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x64_vp9_md5
@@ -0,0 +1,10 @@
+caa8471a8b381d53c3e8fc627946a871 vp90-2-02-size-32x64-32x64-0001.i420
+2cba86ea14c0f28e242625b08f5e9b88 vp90-2-02-size-32x64-32x64-0002.i420
+cea0440ff6569fc82c3030e0340fb649 vp90-2-02-size-32x64-32x64-0003.i420
+c18ef37f1356ade96a2f40af954b31c8 vp90-2-02-size-32x64-32x64-0004.i420
+21e6e549378bcff47913ef292e74dc37 vp90-2-02-size-32x64-32x64-0005.i420
+a9d3d483f74a5afe5d80725ce696fd20 vp90-2-02-size-32x64-32x64-0006.i420
+a436e2586b0963747deaf5e450e2b230 vp90-2-02-size-32x64-32x64-0007.i420
+9daaadf265df56974cb0950843d9fd8c vp90-2-02-size-32x64-32x64-0008.i420
+e0b84714bad2519e62b7d16705fb09d5 vp90-2-02-size-32x64-32x64-0009.i420
+8cdfce574edbe548da7f6cd9a7076b9e vp90-2-02-size-32x64-32x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_32x66.vp9
new file mode 100644
index 0000000..9d96d3d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_32x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_32x66_vp9_md5
new file mode 100644
index 0000000..4a00973
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_32x66_vp9_md5
@@ -0,0 +1,10 @@
+920ea4b8a00d41489d122d641d6e4fe5 vp90-2-02-size-32x66-32x66-0001.i420
+8bfc8d452a79f2978b8e973b77cbf8a8 vp90-2-02-size-32x66-32x66-0002.i420
+09f3f0d31d3377a844fa5385d9b36b9f vp90-2-02-size-32x66-32x66-0003.i420
+df43fae763da9360c8062bb92ee091a8 vp90-2-02-size-32x66-32x66-0004.i420
+445d8c675bb865d1814fcfa6b8a9afd3 vp90-2-02-size-32x66-32x66-0005.i420
+dc7d43db86aac6636724de8790eda555 vp90-2-02-size-32x66-32x66-0006.i420
+d3a9fc272424449ffc5b7e69f8f9948b vp90-2-02-size-32x66-32x66-0007.i420
+11ef33b9bccca54b3703bf24ab55e2d6 vp90-2-02-size-32x66-32x66-0008.i420
+ce31b8bf9b00b427ca956abb800d8034 vp90-2-02-size-32x66-32x66-0009.i420
+e707f824d6e95d482bf3a0b4d52ea069 vp90-2-02-size-32x66-32x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x08.vp9
new file mode 100644
index 0000000..3a1d276
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x08_vp9_md5
new file mode 100644
index 0000000..2940416
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x08_vp9_md5
@@ -0,0 +1,10 @@
+c14f2ba5b4582c9d3a488976814691b3 vp90-2-02-size-34x08-34x8-0001.i420
+4387a4dce19007b7efb810b5a4069749 vp90-2-02-size-34x08-34x8-0002.i420
+ecfe868d28f4861a5612edfd57447a02 vp90-2-02-size-34x08-34x8-0003.i420
+5cba54f568534d29169ac31c8fa505e0 vp90-2-02-size-34x08-34x8-0004.i420
+fe9aab7b3378b9fc3e373ee626b887db vp90-2-02-size-34x08-34x8-0005.i420
+fce72dfc7f9c0cb50ff73761b4d82c1f vp90-2-02-size-34x08-34x8-0006.i420
+d4d98f42b1377e0f0ffaa66aa81d40c3 vp90-2-02-size-34x08-34x8-0007.i420
+65c027646dc95a749ce2d7ad0a6beccc vp90-2-02-size-34x08-34x8-0008.i420
+317b283a0d907270f671272771022e69 vp90-2-02-size-34x08-34x8-0009.i420
+d3e2c008584608502f3e24c5c5f64028 vp90-2-02-size-34x08-34x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x10.vp9
new file mode 100644
index 0000000..336a18a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x10_vp9_md5
new file mode 100644
index 0000000..9e19ab4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x10_vp9_md5
@@ -0,0 +1,10 @@
+fd7212b519783cf4831ce4bff91f2312 vp90-2-02-size-34x10-34x10-0001.i420
+9768722ee939d80a6716865fdebca33d vp90-2-02-size-34x10-34x10-0002.i420
+328ee0f774eeafde00dcc4b9a8f4e9af vp90-2-02-size-34x10-34x10-0003.i420
+f882fa6015fcb042094eadab5fa952cf vp90-2-02-size-34x10-34x10-0004.i420
+4331a3dabeae27d2bf3590eb96ce914a vp90-2-02-size-34x10-34x10-0005.i420
+0e15106bd8e90377f6ed8b464d17159c vp90-2-02-size-34x10-34x10-0006.i420
+8f062653ac2b83f7e541393e838d0e0f vp90-2-02-size-34x10-34x10-0007.i420
+eeb98c1728c1a74510f8bfaf10fc0002 vp90-2-02-size-34x10-34x10-0008.i420
+30bb058a67d6a5ee3693b21cbca5349a vp90-2-02-size-34x10-34x10-0009.i420
+7ce4b79983b3abc37b141a3bea56e0b7 vp90-2-02-size-34x10-34x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x16.vp9
new file mode 100644
index 0000000..41d41f3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x16_vp9_md5
new file mode 100644
index 0000000..1c01cd4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x16_vp9_md5
@@ -0,0 +1,10 @@
+e443c43101be00470c6a61c1a2995b5a vp90-2-02-size-34x16-34x16-0001.i420
+1e79b1b46ec704d360b5fb725913b0f1 vp90-2-02-size-34x16-34x16-0002.i420
+6d5e77cafab6bc43498980c515d299d3 vp90-2-02-size-34x16-34x16-0003.i420
+91c3bba5fd2aa29ee54c8f3783cfe5a2 vp90-2-02-size-34x16-34x16-0004.i420
+9548d07c2a6204694d34e973e8339077 vp90-2-02-size-34x16-34x16-0005.i420
+6819a34c7e3c13bee3ea2b18e12e92fd vp90-2-02-size-34x16-34x16-0006.i420
+f75920457f01f65bf30ba1ec41076d4e vp90-2-02-size-34x16-34x16-0007.i420
+3a04f6cc0c348c21464b173ac6005043 vp90-2-02-size-34x16-34x16-0008.i420
+93a3336374e8cc4dfb2c0b4716ab60ec vp90-2-02-size-34x16-34x16-0009.i420
+148af188b8a2ee93de406a01c2af180d vp90-2-02-size-34x16-34x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x18.vp9
new file mode 100644
index 0000000..9c2f4ea
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x18_vp9_md5
new file mode 100644
index 0000000..74ee172
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x18_vp9_md5
@@ -0,0 +1,10 @@
+ab7eabb355e5163e7451945018fadebd vp90-2-02-size-34x18-34x18-0001.i420
+b9a77cc0c769535808996a6de7b374ff vp90-2-02-size-34x18-34x18-0002.i420
+bd773f11d89091b3c9ebc22d8291dd49 vp90-2-02-size-34x18-34x18-0003.i420
+278c215d6c188752818f07f4d317c0e0 vp90-2-02-size-34x18-34x18-0004.i420
+b59856932c675c1ba587644c23cdb002 vp90-2-02-size-34x18-34x18-0005.i420
+2bcaef04f89326a56025269a68742043 vp90-2-02-size-34x18-34x18-0006.i420
+5abb4a1b96b4bc003cd19a146347c54e vp90-2-02-size-34x18-34x18-0007.i420
+26e36058f451ff80d498ac1c0343489f vp90-2-02-size-34x18-34x18-0008.i420
+57ac43fcc6f1a2c863188aca68d52524 vp90-2-02-size-34x18-34x18-0009.i420
+282467118b5b7a986ccd28d16dab3ea7 vp90-2-02-size-34x18-34x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x32.vp9
new file mode 100644
index 0000000..2c020b4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x32_vp9_md5
new file mode 100644
index 0000000..fb6d77d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x32_vp9_md5
@@ -0,0 +1,10 @@
+7e334867e27046fabf0f39365311c38c vp90-2-02-size-34x32-34x32-0001.i420
+d2a49216ecedea62f546e54c1552f163 vp90-2-02-size-34x32-34x32-0002.i420
+f66e10d1779533e5b6e2b98369134833 vp90-2-02-size-34x32-34x32-0003.i420
+0054b8d4393df58eee87784862a29901 vp90-2-02-size-34x32-34x32-0004.i420
+b9cdf3ebea0d1e3f1e0c42db2e11a3c2 vp90-2-02-size-34x32-34x32-0005.i420
+c08a728d955a559457c82e44c3296148 vp90-2-02-size-34x32-34x32-0006.i420
+d05f4c4a8b0e606525c3d388d26a9351 vp90-2-02-size-34x32-34x32-0007.i420
+78fc2544da88a1a21d6626b0f7bbcf8c vp90-2-02-size-34x32-34x32-0008.i420
+90832c4fed05390377551359bb9a91f7 vp90-2-02-size-34x32-34x32-0009.i420
+5290a0e77081863398f36c7ae192710b vp90-2-02-size-34x32-34x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x34.vp9
new file mode 100644
index 0000000..bcc9c17
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x34_vp9_md5
new file mode 100644
index 0000000..36d92f5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x34_vp9_md5
@@ -0,0 +1,10 @@
+1bb98ba89abf6b86f47a851f8126e1ff vp90-2-02-size-34x34-34x34-0001.i420
+b960cc795c179afe7eec360c57fddd7f vp90-2-02-size-34x34-34x34-0002.i420
+a93cd094a80c542ecb7b6ac7720c5eff vp90-2-02-size-34x34-34x34-0003.i420
+f1cd34e4f0bf9b1238769f028708b742 vp90-2-02-size-34x34-34x34-0004.i420
+f01437ad14450d2136a8fc971f180eb7 vp90-2-02-size-34x34-34x34-0005.i420
+8778230f1182c2227bf1e253bd85df4c vp90-2-02-size-34x34-34x34-0006.i420
+1d1d5cf6c5cc9e73a1fa5b882e441d74 vp90-2-02-size-34x34-34x34-0007.i420
+2f7a1867487c56c252e35225f71adb55 vp90-2-02-size-34x34-34x34-0008.i420
+1d1aea21f70ceed596f22ec32d8712ee vp90-2-02-size-34x34-34x34-0009.i420
+260e66df92f32bc853f4cd4ede692ea4 vp90-2-02-size-34x34-34x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x64.vp9
new file mode 100644
index 0000000..daa63a3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x64_vp9_md5
new file mode 100644
index 0000000..6a6795e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x64_vp9_md5
@@ -0,0 +1,10 @@
+3856635223f578e1e7f7e7250a53cb8d vp90-2-02-size-34x64-34x64-0001.i420
+ee8d7c3a0ea165420d7e733b9e59219a vp90-2-02-size-34x64-34x64-0002.i420
+3d33f06bac22131f04e3411fc216dc02 vp90-2-02-size-34x64-34x64-0003.i420
+7aea667775077de32250dac25fd24bb3 vp90-2-02-size-34x64-34x64-0004.i420
+43fb534551f153c5e9e60240df0bf3b4 vp90-2-02-size-34x64-34x64-0005.i420
+d42b721aa2242d4258d97f840fdcc901 vp90-2-02-size-34x64-34x64-0006.i420
+e876200d720cbe6e36e0ffb775c5ad6c vp90-2-02-size-34x64-34x64-0007.i420
+453078449d8701270564086e58a1d69e vp90-2-02-size-34x64-34x64-0008.i420
+22cb799a817d45a7591489e6faa31cb9 vp90-2-02-size-34x64-34x64-0009.i420
+628dc3f03bf5dd5cae135ad1e4b9ebf7 vp90-2-02-size-34x64-34x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_34x66.vp9
new file mode 100644
index 0000000..ca90995
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_34x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_34x66_vp9_md5
new file mode 100644
index 0000000..af3cde6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_34x66_vp9_md5
@@ -0,0 +1,10 @@
+bf4e568217906ee4b58dc4707bee8ef6 vp90-2-02-size-34x66-34x66-0001.i420
+f823f8c7b6e47ba43215f3becd35208e vp90-2-02-size-34x66-34x66-0002.i420
+1d986d65b502e77764428e21e77503a6 vp90-2-02-size-34x66-34x66-0003.i420
+73520382bc54d6aee165402518dd7b5d vp90-2-02-size-34x66-34x66-0004.i420
+c84e943758f2d7e37126172728838640 vp90-2-02-size-34x66-34x66-0005.i420
+1d4b298da98e4b66b31ad6874f726aa6 vp90-2-02-size-34x66-34x66-0006.i420
+e67748eeb3c818deb8b51d321cd16a9c vp90-2-02-size-34x66-34x66-0007.i420
+4d1514c63e669261beef9e35b04c241e vp90-2-02-size-34x66-34x66-0008.i420
+57705e2131e2129efbc68b74a1e0459c vp90-2-02-size-34x66-34x66-0009.i420
+681acf1b384856d6e544d8e7a79fc628 vp90-2-02-size-34x66-34x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x08.vp9
new file mode 100644
index 0000000..cfb8189
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x08_vp9_md5
new file mode 100644
index 0000000..0b40ce8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x08_vp9_md5
@@ -0,0 +1,10 @@
+d801797c94039b0a166d46e151ec912c vp90-2-02-size-64x08-64x8-0001.i420
+161ec22caa3689b214d9ab993424584b vp90-2-02-size-64x08-64x8-0002.i420
+499b589ecf1873e388c256ce948eabb9 vp90-2-02-size-64x08-64x8-0003.i420
+22bc77650e3df70e3e36f2a1b8d8aa71 vp90-2-02-size-64x08-64x8-0004.i420
+750e40530257a68211596a60de18bffa vp90-2-02-size-64x08-64x8-0005.i420
+4f812a92157e7186642656b59bc28a3d vp90-2-02-size-64x08-64x8-0006.i420
+a3f141cec127a2c2e16740b8dd4ce56a vp90-2-02-size-64x08-64x8-0007.i420
+a5ba9959bf65ab6e254e5b359a3d59b5 vp90-2-02-size-64x08-64x8-0008.i420
+baa72b8a57277d9e9ad4b92aab04f5d1 vp90-2-02-size-64x08-64x8-0009.i420
+4cb9aebb6c9d5bd164461726de201549 vp90-2-02-size-64x08-64x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x10.vp9
new file mode 100644
index 0000000..243962a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x10_vp9_md5
new file mode 100644
index 0000000..acd1ed1
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x10_vp9_md5
@@ -0,0 +1,10 @@
+97eb5fd0599d482662eb0a1def5c5ef2 vp90-2-02-size-64x10-64x10-0001.i420
+dfdc1b61b478dcca8d411021486aa2ec vp90-2-02-size-64x10-64x10-0002.i420
+2cf560f068bdcb9e345951739091808e vp90-2-02-size-64x10-64x10-0003.i420
+33cacb04c0797fc7bd774251e04b7fb9 vp90-2-02-size-64x10-64x10-0004.i420
+7fca126c0542c0dcdcf769b156bd85f5 vp90-2-02-size-64x10-64x10-0005.i420
+8a46c5a48cb5bd34be8e647c127f8d61 vp90-2-02-size-64x10-64x10-0006.i420
+1ddf07562c0b7dc68ed61b8e1a09fcf0 vp90-2-02-size-64x10-64x10-0007.i420
+d75911d5eb7fc75ffc3ee40344fc7ed2 vp90-2-02-size-64x10-64x10-0008.i420
+498329c8a01d950286af11e1fcf3ac07 vp90-2-02-size-64x10-64x10-0009.i420
+7a6ec019df5f3e419d389699094f87c3 vp90-2-02-size-64x10-64x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x16.vp9
new file mode 100644
index 0000000..28663da
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x16_vp9_md5
new file mode 100644
index 0000000..dd67756
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x16_vp9_md5
@@ -0,0 +1,10 @@
+a43068a364cc42619e62406dcf17ddfc vp90-2-02-size-64x16-64x16-0001.i420
+94691f93299bbf5b6ba3022b02b3e069 vp90-2-02-size-64x16-64x16-0002.i420
+3c8fc275490b4daf63ef6d8f9b7f81f6 vp90-2-02-size-64x16-64x16-0003.i420
+96c06031f0fcad49dfed256c5c737d07 vp90-2-02-size-64x16-64x16-0004.i420
+f722d3a51790b55d070d57d3b9a53d0d vp90-2-02-size-64x16-64x16-0005.i420
+a753b3dfe13f5778f9f054e73e512ef1 vp90-2-02-size-64x16-64x16-0006.i420
+fa12cbe6cbc38fa8a38ecbcf1af8833c vp90-2-02-size-64x16-64x16-0007.i420
+cb42303391ef6f76f77d14d2600cce12 vp90-2-02-size-64x16-64x16-0008.i420
+e0c18bb1d4dcc8168b5fdd7c7963987e vp90-2-02-size-64x16-64x16-0009.i420
+581b5291cb60e50326c0dfa6a2d09d8a vp90-2-02-size-64x16-64x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x18.vp9
new file mode 100644
index 0000000..9fb5e37
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x18_vp9_md5
new file mode 100644
index 0000000..4a01c17
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x18_vp9_md5
@@ -0,0 +1,10 @@
+adf7e84a351847683f6a8dd177019e29 vp90-2-02-size-64x18-64x18-0001.i420
+8227cf283a27277fbab3d7826e340337 vp90-2-02-size-64x18-64x18-0002.i420
+a5551b16db948e395537310d12128e76 vp90-2-02-size-64x18-64x18-0003.i420
+4b57ed07dbc15de9ab6143656b2a7e8e vp90-2-02-size-64x18-64x18-0004.i420
+a15489495f0acc41f446e9689e4142d6 vp90-2-02-size-64x18-64x18-0005.i420
+b0a0d5d3ff756e8ae19797455432755c vp90-2-02-size-64x18-64x18-0006.i420
+094a440243d36edcdd3e9d0d070de011 vp90-2-02-size-64x18-64x18-0007.i420
+a780bd61e1abbfbb28581784531608bd vp90-2-02-size-64x18-64x18-0008.i420
+55886a8c7aad65683aa9366a38382512 vp90-2-02-size-64x18-64x18-0009.i420
+5ae5b24383f66720a62ed1001664051f vp90-2-02-size-64x18-64x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x32.vp9
new file mode 100644
index 0000000..c80dcf2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x32_vp9_md5
new file mode 100644
index 0000000..15e0b11
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x32_vp9_md5
@@ -0,0 +1,10 @@
+931ab6a2482c3e84bc7ef8dfbc251307 vp90-2-02-size-64x32-64x32-0001.i420
+3552a9d8470a64ed627a6dbb799b7811 vp90-2-02-size-64x32-64x32-0002.i420
+cae1863fc606a0e3df3e708b7eefdf99 vp90-2-02-size-64x32-64x32-0003.i420
+4b825a07e235c4708b12a726da8e4cdf vp90-2-02-size-64x32-64x32-0004.i420
+0dac578ef616a13be2b9db3c0d775524 vp90-2-02-size-64x32-64x32-0005.i420
+bfd47cbab8285f301777351c8bc5553c vp90-2-02-size-64x32-64x32-0006.i420
+f29f9a0cfeaaae3bdeb26933bc7c17dc vp90-2-02-size-64x32-64x32-0007.i420
+c7f3a4d24dcf72ef195a402eff77d8f6 vp90-2-02-size-64x32-64x32-0008.i420
+88ede6207441a7953cf893032c353663 vp90-2-02-size-64x32-64x32-0009.i420
+258f4e86541813e3edb1fe5332ff4ab1 vp90-2-02-size-64x32-64x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x34.vp9
new file mode 100644
index 0000000..ddd6d64
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x34_vp9_md5
new file mode 100644
index 0000000..2727525
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x34_vp9_md5
@@ -0,0 +1,10 @@
+68d00958a78e6252dd75d632806e2022 vp90-2-02-size-64x34-64x34-0001.i420
+f7b6266e74200a669eecd241db787ee2 vp90-2-02-size-64x34-64x34-0002.i420
+c8b88d43aee037857310edeb74bc66f4 vp90-2-02-size-64x34-64x34-0003.i420
+c6d9a52baf3ca962574bff1364fcb8dc vp90-2-02-size-64x34-64x34-0004.i420
+b384fbf3ceef0affa69f5e81681edc6e vp90-2-02-size-64x34-64x34-0005.i420
+cd473f0c8d1cde98153402123a3ee7cf vp90-2-02-size-64x34-64x34-0006.i420
+c0f320a23c3e39719a3b3590fe3c2ab5 vp90-2-02-size-64x34-64x34-0007.i420
+751207d15a791728c1022f711a25cd68 vp90-2-02-size-64x34-64x34-0008.i420
+7396df89a0d88044cf7527420d193636 vp90-2-02-size-64x34-64x34-0009.i420
+b772dd247838b0c3ed12713447894323 vp90-2-02-size-64x34-64x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x64.vp9
new file mode 100644
index 0000000..af3b43d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x64_vp9_md5
new file mode 100644
index 0000000..9733f63
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x64_vp9_md5
@@ -0,0 +1,10 @@
+35f17db9076fa20368fddfa01543c746 vp90-2-02-size-64x64-64x64-0001.i420
+61cd775dfc177262da9a91d3912e6718 vp90-2-02-size-64x64-64x64-0002.i420
+8b8cf175f91425d703332b22b46c1c0e vp90-2-02-size-64x64-64x64-0003.i420
+6041afbdd81e228f8f16384d3f9e988e vp90-2-02-size-64x64-64x64-0004.i420
+d30bd08897b50f518920014c7fa55df9 vp90-2-02-size-64x64-64x64-0005.i420
+fb67222a183876b502f93e48bb779b70 vp90-2-02-size-64x64-64x64-0006.i420
+60830425ca1dcf3df4ee9c6cd75f066a vp90-2-02-size-64x64-64x64-0007.i420
+3e178df858f7fcaa2552a1c5c719b5cc vp90-2-02-size-64x64-64x64-0008.i420
+66718eb0c3981beb7c1119df8a2cd27e vp90-2-02-size-64x64-64x64-0009.i420
+7c1912448c7756f7451888050760d73d vp90-2-02-size-64x64-64x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_64x66.vp9
new file mode 100644
index 0000000..eecb1c0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_64x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_64x66_vp9_md5
new file mode 100644
index 0000000..1c4d7e9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_64x66_vp9_md5
@@ -0,0 +1,10 @@
+88587de65acfc85ff56daac8ef5d12e6 vp90-2-02-size-64x66-64x66-0001.i420
+be41f6c788b929b5b6b27c5674f40abd vp90-2-02-size-64x66-64x66-0002.i420
+04ab3f88ca062a6911405fd84c7e9de4 vp90-2-02-size-64x66-64x66-0003.i420
+231436e0a68d19d3882f285d38aca3fb vp90-2-02-size-64x66-64x66-0004.i420
+1a067e147a6740bb4ce57c4184437eea vp90-2-02-size-64x66-64x66-0005.i420
+be0c47e06c7e9439570473adf4713f5f vp90-2-02-size-64x66-64x66-0006.i420
+a213b0611247eafab0711748c25e88a0 vp90-2-02-size-64x66-64x66-0007.i420
+b1df495aa3afb74399f91c74b527b93c vp90-2-02-size-64x66-64x66-0008.i420
+46319f21069541e1ee1652621b957860 vp90-2-02-size-64x66-64x66-0009.i420
+313517a5721b2b14683e7eefc83e51b1 vp90-2-02-size-64x66-64x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x08.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x08.vp9
new file mode 100644
index 0000000..3b05d4f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x08.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x08_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x08_vp9_md5
new file mode 100644
index 0000000..1879fe4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x08_vp9_md5
@@ -0,0 +1,10 @@
+3b16847e60786706fc339abc452746ff vp90-2-02-size-66x08-66x8-0001.i420
+365a5951cb127d6df183fe5d5000f493 vp90-2-02-size-66x08-66x8-0002.i420
+6d4bceb815ca7717c4a3f86a6670703a vp90-2-02-size-66x08-66x8-0003.i420
+5a0a03d4788934285448c85788ae8d71 vp90-2-02-size-66x08-66x8-0004.i420
+8712f9a82d07447e7a0d0a37ddc3858d vp90-2-02-size-66x08-66x8-0005.i420
+cff32e6c183c16962207a86d7c6cf0a0 vp90-2-02-size-66x08-66x8-0006.i420
+dc933d90f87110651d7efb39854d3d46 vp90-2-02-size-66x08-66x8-0007.i420
+d1299562a022521f0c3cb30668f83b6d vp90-2-02-size-66x08-66x8-0008.i420
+5054254ca125d7c7e6df4001397170cd vp90-2-02-size-66x08-66x8-0009.i420
+a6bd7c7c0b02afa8d25f911ec847c61a vp90-2-02-size-66x08-66x8-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x10.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x10.vp9
new file mode 100644
index 0000000..32c62e4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x10.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x10_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x10_vp9_md5
new file mode 100644
index 0000000..56a9c16
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x10_vp9_md5
@@ -0,0 +1,10 @@
+7cbd8c6b2fb35c0c3063cb7a379944c9 vp90-2-02-size-66x10-66x10-0001.i420
+14062e74b98bed1ca982f408bc14326c vp90-2-02-size-66x10-66x10-0002.i420
+f6d6868d849aa74b27df1c5f40c7096e vp90-2-02-size-66x10-66x10-0003.i420
+719c8d7e3769466ee8e3dca3f4747a0e vp90-2-02-size-66x10-66x10-0004.i420
+a72e1a7a4c82ec09ea77f87b0e6f25aa vp90-2-02-size-66x10-66x10-0005.i420
+a5163d142b429afa155cc2f1401a0b8a vp90-2-02-size-66x10-66x10-0006.i420
+27762d813dd1f80d6aaed5f197124fa5 vp90-2-02-size-66x10-66x10-0007.i420
+02e94454660f3528abbde8f50e94288f vp90-2-02-size-66x10-66x10-0008.i420
+1d57dcfa57a55d96f14cfe471aac2e0b vp90-2-02-size-66x10-66x10-0009.i420
+7804477923c0cd067bd09ebca3529775 vp90-2-02-size-66x10-66x10-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x16.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x16.vp9
new file mode 100644
index 0000000..6a0d1ac
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x16.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x16_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x16_vp9_md5
new file mode 100644
index 0000000..2aae0a2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x16_vp9_md5
@@ -0,0 +1,10 @@
+fa2f292d273c37dc2804a70d1cae1e9d vp90-2-02-size-66x16-66x16-0001.i420
+ba75d90652c021bc7ca061352e6e94ce vp90-2-02-size-66x16-66x16-0002.i420
+e65d9a205bd17d100e50c7b6a7ea772d vp90-2-02-size-66x16-66x16-0003.i420
+46f9e9ff891576b9462f21d48b7b9e2b vp90-2-02-size-66x16-66x16-0004.i420
+d23cedacf3a37cf6b2774e0b18b6b9d7 vp90-2-02-size-66x16-66x16-0005.i420
+84329f7716a6db5a7e64a68a1155bfc6 vp90-2-02-size-66x16-66x16-0006.i420
+ad62286b0e13f4e54df4445cdd4fd4e3 vp90-2-02-size-66x16-66x16-0007.i420
+4511529eb24b21eb63e280070f888642 vp90-2-02-size-66x16-66x16-0008.i420
+4e1c122df1785e0e9134c43c85082e05 vp90-2-02-size-66x16-66x16-0009.i420
+ac3a3747a00be3f9f58155648fcf9b24 vp90-2-02-size-66x16-66x16-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x18.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x18.vp9
new file mode 100644
index 0000000..e2535f0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x18.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x18_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x18_vp9_md5
new file mode 100644
index 0000000..05e3eaf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x18_vp9_md5
@@ -0,0 +1,10 @@
+fda5ad9bf70a51b3a41bdcabf2cce32a vp90-2-02-size-66x18-66x18-0001.i420
+91916fb20ad542a7a3ad276e6505f9b0 vp90-2-02-size-66x18-66x18-0002.i420
+e18e5d11aec483c76afd68f7e64415a4 vp90-2-02-size-66x18-66x18-0003.i420
+c13da01c2b6c09101bda7af93ad5fd07 vp90-2-02-size-66x18-66x18-0004.i420
+ed8d2568b2ad9c7bd980cba0d3b95cff vp90-2-02-size-66x18-66x18-0005.i420
+e6f3cf312b69d37579e77f2e52cc936b vp90-2-02-size-66x18-66x18-0006.i420
+e509f3682e9c4bcdb0889e044b1979b7 vp90-2-02-size-66x18-66x18-0007.i420
+acc3945e557cd7a9642f08a656444976 vp90-2-02-size-66x18-66x18-0008.i420
+44ddd03aa8f03ba393f12fc6a1b3fc17 vp90-2-02-size-66x18-66x18-0009.i420
+fdd3e68132c742d9f0cf0ea6fff2a074 vp90-2-02-size-66x18-66x18-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x32.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x32.vp9
new file mode 100644
index 0000000..445d975
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x32.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x32_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x32_vp9_md5
new file mode 100644
index 0000000..996f32b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x32_vp9_md5
@@ -0,0 +1,10 @@
+013cd22aea6bfeccc8ec809abd52be5c vp90-2-02-size-66x32-66x32-0001.i420
+0980adfb0ef879b3c960797272f025ad vp90-2-02-size-66x32-66x32-0002.i420
+d1411ffa0429befb8c71d3ab45acee92 vp90-2-02-size-66x32-66x32-0003.i420
+6c6f825379eaf21709a45be77def7a63 vp90-2-02-size-66x32-66x32-0004.i420
+bab632ef00a080739a41c692f2b21c3a vp90-2-02-size-66x32-66x32-0005.i420
+fc0f6045aca252f2e904730227b8f337 vp90-2-02-size-66x32-66x32-0006.i420
+c8dbea209329463bfd9238a11b8d5b17 vp90-2-02-size-66x32-66x32-0007.i420
+457247bf4186ed8459e0a1564f0e68f2 vp90-2-02-size-66x32-66x32-0008.i420
+baa55e20bd7c73960b080d8a0c8db4d5 vp90-2-02-size-66x32-66x32-0009.i420
+dc8933e8edc98cd0cfca44ae22997c62 vp90-2-02-size-66x32-66x32-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x34.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x34.vp9
new file mode 100644
index 0000000..8705e9f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x34.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x34_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x34_vp9_md5
new file mode 100644
index 0000000..ca0e251
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x34_vp9_md5
@@ -0,0 +1,10 @@
+6821eb3fcd1d10db32eff70468dcf9c1 vp90-2-02-size-66x34-66x34-0001.i420
+ed0094d347d9f250d46b4903cbc14801 vp90-2-02-size-66x34-66x34-0002.i420
+fd018555dc9a62b8074d46e7c0fd0b40 vp90-2-02-size-66x34-66x34-0003.i420
+05d5baf9f2e62bbeeb3809a099e84147 vp90-2-02-size-66x34-66x34-0004.i420
+7a150c265214269c08e05fe4f296122d vp90-2-02-size-66x34-66x34-0005.i420
+9a7ae61d4bb125ee4c4ccce9cc1c3664 vp90-2-02-size-66x34-66x34-0006.i420
+5a88fd6d96dcbc4255e98dfe19ff96b8 vp90-2-02-size-66x34-66x34-0007.i420
+4192c273a46b2b196c871ead0e61ec71 vp90-2-02-size-66x34-66x34-0008.i420
+e79ebfc47e755f5db221f392c3216278 vp90-2-02-size-66x34-66x34-0009.i420
+b995c5f483a2e553baf4f66d1a47fc57 vp90-2-02-size-66x34-66x34-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x64.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x64.vp9
new file mode 100644
index 0000000..c91df34
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x64.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x64_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x64_vp9_md5
new file mode 100644
index 0000000..9802722
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x64_vp9_md5
@@ -0,0 +1,10 @@
+929086fbb3e117bd53110b64c1ee915b vp90-2-02-size-66x64-66x64-0001.i420
+9ed45f5e40dd2393434e14a0c0160c63 vp90-2-02-size-66x64-66x64-0002.i420
+5cdade692b1baf23e61896da18e3e44f vp90-2-02-size-66x64-66x64-0003.i420
+11a2ebac61a3f826ec41c8031899e55c vp90-2-02-size-66x64-66x64-0004.i420
+621a1e0142b94d14db9c2121553a11fb vp90-2-02-size-66x64-66x64-0005.i420
+029a29590f7255f1bc9ff9b7a000ca25 vp90-2-02-size-66x64-66x64-0006.i420
+5fde42becf6bf054d04e2a0fa1b2d55e vp90-2-02-size-66x64-66x64-0007.i420
+5b8ba552cef1931e1412fb4f3420748b vp90-2-02-size-66x64-66x64-0008.i420
+d41cd7d418f6ec1db802a01a90cfee1e vp90-2-02-size-66x64-66x64-0009.i420
+cea99c93a84a82edff8c6069d131453f vp90-2-02-size-66x64-66x64-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x66.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_66x66.vp9
new file mode 100644
index 0000000..e50c30a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x66.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_66x66_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_66x66_vp9_md5
new file mode 100644
index 0000000..4cf3ed2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_66x66_vp9_md5
@@ -0,0 +1,10 @@
+69f9028d52f95d2e7f986c57b19fc018 vp90-2-02-size-66x66-66x66-0001.i420
+068e611f62b3f6222f6b1699748c8fbf vp90-2-02-size-66x66-66x66-0002.i420
+3d3fec78ff2274241a7958f17a773a19 vp90-2-02-size-66x66-66x66-0003.i420
+93d71ef1a2d00c7e70e76ccc1859143d vp90-2-02-size-66x66-66x66-0004.i420
+5a35a640d52bc0930825b963b0b9e830 vp90-2-02-size-66x66-66x66-0005.i420
+782223239e6b1ca1bedbd25d9652a07c vp90-2-02-size-66x66-66x66-0006.i420
+a4b5e8a319cbc9a12d3e36127c7f0fbb vp90-2-02-size-66x66-66x66-0007.i420
+a3e2d9a78fa42b3c817aadfd31fd2d16 vp90-2-02-size-66x66-66x66-0008.i420
+e9fc6b83535735f46006f3e4b376755f vp90-2-02-size-66x66-66x66-0009.i420
+80223f600dfe86021bd0e83fecdc4b2b vp90-2-02-size-66x66-66x66-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_lf_1920x1080.vp9 b/tests/tests/media/res/raw/vp90_2_02_size_lf_1920x1080.vp9
new file mode 100644
index 0000000..d7cfc93
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_lf_1920x1080.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_02_size_lf_1920x1080_vp9_md5 b/tests/tests/media/res/raw/vp90_2_02_size_lf_1920x1080_vp9_md5
new file mode 100644
index 0000000..557ac7a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_02_size_lf_1920x1080_vp9_md5
@@ -0,0 +1,217 @@
+3fb5a1b268b017332fda7fa981032c2c vp90-2-02-size-lf-1920x1080-1920x1080-0001.i420
+7380f42c862bb0418274010f71f8291f vp90-2-02-size-lf-1920x1080-1920x1080-0002.i420
+1931968e92c34f693582d1ae28e7a145 vp90-2-02-size-lf-1920x1080-1920x1080-0003.i420
+40606221248726f3412d8e08e489a94f vp90-2-02-size-lf-1920x1080-1920x1080-0004.i420
+5ecd3fd1d4b607e3d84fb597a948d84b vp90-2-02-size-lf-1920x1080-1920x1080-0005.i420
+db805d6f9289f1525c4ea594bf323fdc vp90-2-02-size-lf-1920x1080-1920x1080-0006.i420
+7584c857279bfcf6e5e1e29557c2a6f0 vp90-2-02-size-lf-1920x1080-1920x1080-0007.i420
+bf436864c58c4d2db1d9b31ce06a8f70 vp90-2-02-size-lf-1920x1080-1920x1080-0008.i420
+9712ccf78bcddc0c44c221c2767e1f28 vp90-2-02-size-lf-1920x1080-1920x1080-0009.i420
+3071176342e59678d99dd8686336e476 vp90-2-02-size-lf-1920x1080-1920x1080-0010.i420
+92cfa56092e8e4d5269de441d31ec739 vp90-2-02-size-lf-1920x1080-1920x1080-0011.i420
+d0bc77ad1997bc38f312846a40d11a16 vp90-2-02-size-lf-1920x1080-1920x1080-0012.i420
+c656c39e3527eee973033b42d4b9deef vp90-2-02-size-lf-1920x1080-1920x1080-0013.i420
+725ccfe5d0736997aa78f7d948692cdb vp90-2-02-size-lf-1920x1080-1920x1080-0014.i420
+51f2245ebc2da1e3bdd0708e9d18e1eb vp90-2-02-size-lf-1920x1080-1920x1080-0015.i420
+530c48d99fad9cddad22ee67ba4fd4d4 vp90-2-02-size-lf-1920x1080-1920x1080-0016.i420
+d55a6ebe71df8d47ac0f2b2f243f740a vp90-2-02-size-lf-1920x1080-1920x1080-0017.i420
+aa84ff7d5dc665441376f8a75bd9bf05 vp90-2-02-size-lf-1920x1080-1920x1080-0018.i420
+70459811c09abf51e7e421656bff1939 vp90-2-02-size-lf-1920x1080-1920x1080-0019.i420
+bb69e3d69ef55a6d19506dd556168901 vp90-2-02-size-lf-1920x1080-1920x1080-0020.i420
+4f1daad761f0949509ffd9873ca03cd4 vp90-2-02-size-lf-1920x1080-1920x1080-0021.i420
+37a037e9de60b411701fda7706db37d6 vp90-2-02-size-lf-1920x1080-1920x1080-0022.i420
+09869838e806717791fe867b018d18ff vp90-2-02-size-lf-1920x1080-1920x1080-0023.i420
+367385d264306ddd25231bb9f8681160 vp90-2-02-size-lf-1920x1080-1920x1080-0024.i420
+42c9da4939d435fcec3def2fa2bc5e26 vp90-2-02-size-lf-1920x1080-1920x1080-0025.i420
+26da302e6e86a632dfa8d8a78e83e269 vp90-2-02-size-lf-1920x1080-1920x1080-0026.i420
+8387287bfa4e62dd575941fab6f95f96 vp90-2-02-size-lf-1920x1080-1920x1080-0027.i420
+7fcc408015aed7f70c0c2321b61d166d vp90-2-02-size-lf-1920x1080-1920x1080-0028.i420
+2394b1c14a156421cc7b30fa95c1a49b vp90-2-02-size-lf-1920x1080-1920x1080-0029.i420
+34d91c69395380155f6f1020cda78bf9 vp90-2-02-size-lf-1920x1080-1920x1080-0030.i420
+3f081ccd624b2648b7fde66e23b05e1d vp90-2-02-size-lf-1920x1080-1920x1080-0031.i420
+ca08738b7c81f2f10ea2f65bf5fd7876 vp90-2-02-size-lf-1920x1080-1920x1080-0032.i420
+f65c4dc7c172666ba3bb9bd402d5767c vp90-2-02-size-lf-1920x1080-1920x1080-0033.i420
+d7ea91467fea6c268b6cd8da9067d12b vp90-2-02-size-lf-1920x1080-1920x1080-0034.i420
+9888aa4a9b3ff09ada838b5ab0f1216c vp90-2-02-size-lf-1920x1080-1920x1080-0035.i420
+015d788822a605d03877454c8ffd065a vp90-2-02-size-lf-1920x1080-1920x1080-0036.i420
+d9d6a53eed5627764c107aafaa64d9a8 vp90-2-02-size-lf-1920x1080-1920x1080-0037.i420
+0b4a40dc0a6a1f5caf16ddd4dde26186 vp90-2-02-size-lf-1920x1080-1920x1080-0038.i420
+4a3f4c2e6d559a1a93b50e716dddf0bf vp90-2-02-size-lf-1920x1080-1920x1080-0039.i420
+d10f631f4a15b6f1060233a6519eefcc vp90-2-02-size-lf-1920x1080-1920x1080-0040.i420
+cc650873b637c244cb1415e39051d013 vp90-2-02-size-lf-1920x1080-1920x1080-0041.i420
+44a697f932e97b7f53a989e429fdca29 vp90-2-02-size-lf-1920x1080-1920x1080-0042.i420
+a09c7c567353412a36776398975fbe6a vp90-2-02-size-lf-1920x1080-1920x1080-0043.i420
+49e3469e2b27fc776bcc0e146910ce2b vp90-2-02-size-lf-1920x1080-1920x1080-0044.i420
+dd3261b098648b62fa0eab900b0056ba vp90-2-02-size-lf-1920x1080-1920x1080-0045.i420
+853f90bb3e23e837ad0cb33106c2256f vp90-2-02-size-lf-1920x1080-1920x1080-0046.i420
+0df1eadd74d643e029188f242af2f533 vp90-2-02-size-lf-1920x1080-1920x1080-0047.i420
+c1d3b56a0a622b176b81400421e87176 vp90-2-02-size-lf-1920x1080-1920x1080-0048.i420
+3c723084af1b727f78fdb9a0e5912a58 vp90-2-02-size-lf-1920x1080-1920x1080-0049.i420
+9806a519be5c399ae8c2b816772786ec vp90-2-02-size-lf-1920x1080-1920x1080-0050.i420
+f25fd27140575595c5f944446e57e502 vp90-2-02-size-lf-1920x1080-1920x1080-0051.i420
+8c8e4f402372d76e2844794d2ddada43 vp90-2-02-size-lf-1920x1080-1920x1080-0052.i420
+c2cce3cc8291978008779f567e912361 vp90-2-02-size-lf-1920x1080-1920x1080-0053.i420
+d3d2819296938ded08b07b2206387afd vp90-2-02-size-lf-1920x1080-1920x1080-0054.i420
+fce62f1e083bf305f966696617549fc8 vp90-2-02-size-lf-1920x1080-1920x1080-0055.i420
+70ccdb87e5d4458ab60fb6b7a263880f vp90-2-02-size-lf-1920x1080-1920x1080-0056.i420
+a8def4b2a416924ac1a8933901e6cdee vp90-2-02-size-lf-1920x1080-1920x1080-0057.i420
+a4f09f6e2f534716e0ab92c094cd0525 vp90-2-02-size-lf-1920x1080-1920x1080-0058.i420
+91e264c9da9dd14b631ef6483a458ead vp90-2-02-size-lf-1920x1080-1920x1080-0059.i420
+8506e8b6033f50212c7a4fb751074667 vp90-2-02-size-lf-1920x1080-1920x1080-0060.i420
+eb14b107652f8f71ff06b1f73fbc8ec7 vp90-2-02-size-lf-1920x1080-1920x1080-0061.i420
+4684a67783e8663bdf275352108f4eef vp90-2-02-size-lf-1920x1080-1920x1080-0062.i420
+9568285e9a9542f5a708a31e2e157c5b vp90-2-02-size-lf-1920x1080-1920x1080-0063.i420
+b5349702a8cb8679a362ba8bc550bf7c vp90-2-02-size-lf-1920x1080-1920x1080-0064.i420
+fb7920dc58fd81ddf221fc9031fbc19f vp90-2-02-size-lf-1920x1080-1920x1080-0065.i420
+b8f752ad92003e481c94beb3b8599214 vp90-2-02-size-lf-1920x1080-1920x1080-0066.i420
+3d93fc99118832ac7c3897f3e9b3a82e vp90-2-02-size-lf-1920x1080-1920x1080-0067.i420
+98003f945aa8ba7aae4d9f6255002f62 vp90-2-02-size-lf-1920x1080-1920x1080-0068.i420
+a18ff6d6fa7645f922de2f3ba4053f49 vp90-2-02-size-lf-1920x1080-1920x1080-0069.i420
+1232126ef24ff4787b11b32223d34018 vp90-2-02-size-lf-1920x1080-1920x1080-0070.i420
+a83f92c62e008939b3de91cdf9c1282f vp90-2-02-size-lf-1920x1080-1920x1080-0071.i420
+cd47127ea0b864e5636222b40cdb5fbe vp90-2-02-size-lf-1920x1080-1920x1080-0072.i420
+544233ce095abea8ffe427a603224ddd vp90-2-02-size-lf-1920x1080-1920x1080-0073.i420
+7192883aca7eda74dd7e61d1cc6f6e2e vp90-2-02-size-lf-1920x1080-1920x1080-0074.i420
+e8db34581dd264810ad683cd6475cf23 vp90-2-02-size-lf-1920x1080-1920x1080-0075.i420
+c215af24670915f3a123beb970ccba22 vp90-2-02-size-lf-1920x1080-1920x1080-0076.i420
+40d89931ddef819030a46d81e114f0b5 vp90-2-02-size-lf-1920x1080-1920x1080-0077.i420
+064781c2e9e9d564c9098be2aa5b6299 vp90-2-02-size-lf-1920x1080-1920x1080-0078.i420
+9ebab2d14446bdd11b62a6b308889b64 vp90-2-02-size-lf-1920x1080-1920x1080-0079.i420
+77ca0761cab449ea90bc8b1e1de5ae3a vp90-2-02-size-lf-1920x1080-1920x1080-0080.i420
+74cb71b2755157dc7c1ef211b2346270 vp90-2-02-size-lf-1920x1080-1920x1080-0081.i420
+23ce88228df42b9e69ad3f4f25dd20cf vp90-2-02-size-lf-1920x1080-1920x1080-0082.i420
+52ac5c9e14482dfde27ad838145c5986 vp90-2-02-size-lf-1920x1080-1920x1080-0083.i420
+929381d60199bb8c250324ca96323008 vp90-2-02-size-lf-1920x1080-1920x1080-0084.i420
+94f9ca3acbe3ed61bffec3f48e1dc43a vp90-2-02-size-lf-1920x1080-1920x1080-0085.i420
+955a4095051cdf3699e5385396a04d69 vp90-2-02-size-lf-1920x1080-1920x1080-0086.i420
+dd784f3a18eae98cae4f795f854d6f03 vp90-2-02-size-lf-1920x1080-1920x1080-0087.i420
+1ebeb7d3d528292c8ae1b54b30692c81 vp90-2-02-size-lf-1920x1080-1920x1080-0088.i420
+f38b83c5b2827c4efddcb6777fd6cd5d vp90-2-02-size-lf-1920x1080-1920x1080-0089.i420
+011dff2cf18e5b4bac6035edf57372d6 vp90-2-02-size-lf-1920x1080-1920x1080-0090.i420
+a1e8ae0f840b6aeddf283f44aa57262e vp90-2-02-size-lf-1920x1080-1920x1080-0091.i420
+bf8f75c177756e4e8c8ad0d494b7921c vp90-2-02-size-lf-1920x1080-1920x1080-0092.i420
+d3e9bf1a44f61e47a3d0f4ca04921a11 vp90-2-02-size-lf-1920x1080-1920x1080-0093.i420
+874f5b4db9dfdb78d9a654a9ce3da4ba vp90-2-02-size-lf-1920x1080-1920x1080-0094.i420
+a8f7ef85e67a1b3c6c730565e0e1ab3e vp90-2-02-size-lf-1920x1080-1920x1080-0095.i420
+33d6e20c9921719b4dcd9ccdcf242ebf vp90-2-02-size-lf-1920x1080-1920x1080-0096.i420
+ee13704be5bb72bc91e05dc07154c8b4 vp90-2-02-size-lf-1920x1080-1920x1080-0097.i420
+8edfa18ab4a51243581302b7b12655c5 vp90-2-02-size-lf-1920x1080-1920x1080-0098.i420
+4d71c47f48e498c525b3a2907b4dad10 vp90-2-02-size-lf-1920x1080-1920x1080-0099.i420
+6de62f06881c7db2e37391f3928f9ac1 vp90-2-02-size-lf-1920x1080-1920x1080-0100.i420
+70f76a47c7ed5568ff4d21c53c58482e vp90-2-02-size-lf-1920x1080-1920x1080-0101.i420
+e7faf1645e75a6d0927336c08a018a34 vp90-2-02-size-lf-1920x1080-1920x1080-0102.i420
+e206df8ed03f809e31f704863851ec77 vp90-2-02-size-lf-1920x1080-1920x1080-0103.i420
+03eb13cf9426514e58deeda33f4766d0 vp90-2-02-size-lf-1920x1080-1920x1080-0104.i420
+e06bc2064d306de26356f6d67c2bc21b vp90-2-02-size-lf-1920x1080-1920x1080-0105.i420
+dd8a993039b6d9c78e2f03c7efcb4984 vp90-2-02-size-lf-1920x1080-1920x1080-0106.i420
+26cb793df8bc7f1ddcd9bd897e877ef0 vp90-2-02-size-lf-1920x1080-1920x1080-0107.i420
+7e3d32618b104c9c47d4464aa2df4709 vp90-2-02-size-lf-1920x1080-1920x1080-0108.i420
+64b1e12d7b87decd877e6c23ffd275d7 vp90-2-02-size-lf-1920x1080-1920x1080-0109.i420
+323ddc3a19c198f7768dacaf6faad602 vp90-2-02-size-lf-1920x1080-1920x1080-0110.i420
+126d984b9bdaf3397ea4ebec52775e7f vp90-2-02-size-lf-1920x1080-1920x1080-0111.i420
+76a4586be73d0401c339790c1045abab vp90-2-02-size-lf-1920x1080-1920x1080-0112.i420
+68466c976fb0309ada2cc7bc514c7d78 vp90-2-02-size-lf-1920x1080-1920x1080-0113.i420
+38135b5505f21ec8d23f97cb29ef1161 vp90-2-02-size-lf-1920x1080-1920x1080-0114.i420
+d657d27a111e9d81b1fbedc7f9c035c9 vp90-2-02-size-lf-1920x1080-1920x1080-0115.i420
+f399d1dc319f560206f09ca5fb59c837 vp90-2-02-size-lf-1920x1080-1920x1080-0116.i420
+269b8a8582e28e11ca3d21dc0f4dc2a6 vp90-2-02-size-lf-1920x1080-1920x1080-0117.i420
+3550fd48042d272f051bb4a6fc76c9df vp90-2-02-size-lf-1920x1080-1920x1080-0118.i420
+5be1f4ed7eea3b62d6c55003ded2906a vp90-2-02-size-lf-1920x1080-1920x1080-0119.i420
+7c607aade4b3451f9a081367584ae5f7 vp90-2-02-size-lf-1920x1080-1920x1080-0120.i420
+a724b1ee8504955503aca7af81425008 vp90-2-02-size-lf-1920x1080-1920x1080-0121.i420
+f58ea230bd73fa111982093742f22055 vp90-2-02-size-lf-1920x1080-1920x1080-0122.i420
+8ad4a70efa7bbc936049de2cd5b973b8 vp90-2-02-size-lf-1920x1080-1920x1080-0123.i420
+4ecbe738e3d31d546332ae248e6ba075 vp90-2-02-size-lf-1920x1080-1920x1080-0124.i420
+507a6fe3e6c95dfec41950382ed49f0e vp90-2-02-size-lf-1920x1080-1920x1080-0125.i420
+833dc6d11dbfc1fa8465b292a66afa32 vp90-2-02-size-lf-1920x1080-1920x1080-0126.i420
+0ac2d4983e91ba36a69d11ae9a32f31a vp90-2-02-size-lf-1920x1080-1920x1080-0127.i420
+0e61c144b842d46b7f63f433dc7be802 vp90-2-02-size-lf-1920x1080-1920x1080-0128.i420
+e93dc18eddef0a93ba652ed898fc4898 vp90-2-02-size-lf-1920x1080-1920x1080-0129.i420
+6745736a1f8ce3dae8532a007023ac6a vp90-2-02-size-lf-1920x1080-1920x1080-0130.i420
+75f9739dc3e003fdb356221a5654c0e4 vp90-2-02-size-lf-1920x1080-1920x1080-0131.i420
+d189cf9fffb8118f31a294deab61585a vp90-2-02-size-lf-1920x1080-1920x1080-0132.i420
+2738879f462aca9015e212e644420b7b vp90-2-02-size-lf-1920x1080-1920x1080-0133.i420
+eff4b276b3c4f454b0822ae4f8d88a0b vp90-2-02-size-lf-1920x1080-1920x1080-0134.i420
+2e461ae7d93bb4cfd4e072a35b651d17 vp90-2-02-size-lf-1920x1080-1920x1080-0135.i420
+bf9a82ea0e3628e4fd1eeb03cb1f50bc vp90-2-02-size-lf-1920x1080-1920x1080-0136.i420
+c8dff3e50d37f9e1ce8b92a0762c57be vp90-2-02-size-lf-1920x1080-1920x1080-0137.i420
+51e6f9efc88a795de0a4d16a6a71d497 vp90-2-02-size-lf-1920x1080-1920x1080-0138.i420
+761b5005e7f8ab8185ccedb660ded250 vp90-2-02-size-lf-1920x1080-1920x1080-0139.i420
+f98da0c03436b1c759d368b9d42db679 vp90-2-02-size-lf-1920x1080-1920x1080-0140.i420
+dec3590e5c11737670703e73ed69783f vp90-2-02-size-lf-1920x1080-1920x1080-0141.i420
+0481f4aec0c9eafb3f9a10cf80c0b056 vp90-2-02-size-lf-1920x1080-1920x1080-0142.i420
+67478cb1e4de699d529046f983105477 vp90-2-02-size-lf-1920x1080-1920x1080-0143.i420
+80f371f7fa43cab698b832a4010e5a88 vp90-2-02-size-lf-1920x1080-1920x1080-0144.i420
+4e9095ab5204a387f63118949bb90f9e vp90-2-02-size-lf-1920x1080-1920x1080-0145.i420
+f943ce3342b90b01fabd3d5bc779bb01 vp90-2-02-size-lf-1920x1080-1920x1080-0146.i420
+1b12d49c5685111fa4faa8edc8b683ad vp90-2-02-size-lf-1920x1080-1920x1080-0147.i420
+8ee848ae53f7b86a254e49562bbfe849 vp90-2-02-size-lf-1920x1080-1920x1080-0148.i420
+2d83c434c41329ae3a8b56c10a27f2e7 vp90-2-02-size-lf-1920x1080-1920x1080-0149.i420
+af6a63fc13b919dabedd86db735990f3 vp90-2-02-size-lf-1920x1080-1920x1080-0150.i420
+a807fce07a52227202dcdcbbfb4eb1bc vp90-2-02-size-lf-1920x1080-1920x1080-0151.i420
+95aebea323577226684914c6b74830c5 vp90-2-02-size-lf-1920x1080-1920x1080-0152.i420
+65d64ebdaadb116608f06add0e8fada2 vp90-2-02-size-lf-1920x1080-1920x1080-0153.i420
+b064af776f8c562ea6b41e0c74710869 vp90-2-02-size-lf-1920x1080-1920x1080-0154.i420
+26291594af160501023eb0035443b7c3 vp90-2-02-size-lf-1920x1080-1920x1080-0155.i420
+79a414d560d3e36314c981f1e30e053b vp90-2-02-size-lf-1920x1080-1920x1080-0156.i420
+3455e01e2cd146aefbad54cb032b15f1 vp90-2-02-size-lf-1920x1080-1920x1080-0157.i420
+eaa2e271058202cbc0933dea8f46f570 vp90-2-02-size-lf-1920x1080-1920x1080-0158.i420
+42da27c94aaa56ae27fddf75bf51f47f vp90-2-02-size-lf-1920x1080-1920x1080-0159.i420
+746cca013c7b6df41e3233214ca7a5d7 vp90-2-02-size-lf-1920x1080-1920x1080-0160.i420
+ab20ad95d6b3e0d689186cde51e4a86a vp90-2-02-size-lf-1920x1080-1920x1080-0161.i420
+b8a02e44615a697da3de946e8cf4e8e4 vp90-2-02-size-lf-1920x1080-1920x1080-0162.i420
+4df5b10cb1c784362035f69bdb183be0 vp90-2-02-size-lf-1920x1080-1920x1080-0163.i420
+f2e5dd616e8125b1b46c410141180fb0 vp90-2-02-size-lf-1920x1080-1920x1080-0164.i420
+e09ab4ca180cb477a3a87bc8fd1e2ce0 vp90-2-02-size-lf-1920x1080-1920x1080-0165.i420
+5ee431b26d6c83689bf18eb8d805f31e vp90-2-02-size-lf-1920x1080-1920x1080-0166.i420
+bca8aaf030c959ac37c3e084be6cf8b3 vp90-2-02-size-lf-1920x1080-1920x1080-0167.i420
+8dd977323d8a5dba5c98c6671821e066 vp90-2-02-size-lf-1920x1080-1920x1080-0168.i420
+aed8ef2c20f9726542c78fade0fb0968 vp90-2-02-size-lf-1920x1080-1920x1080-0169.i420
+e19775ba9c5b6dbf1e84fd0531bd1f2a vp90-2-02-size-lf-1920x1080-1920x1080-0170.i420
+a69c5daf6e6e3b579a3430fc95f37dac vp90-2-02-size-lf-1920x1080-1920x1080-0171.i420
+3503bc793f86b75d9aa1c9c51b2d0f6f vp90-2-02-size-lf-1920x1080-1920x1080-0172.i420
+bdcee02e245b92acf06588370df2e5e6 vp90-2-02-size-lf-1920x1080-1920x1080-0173.i420
+8bbb9460d0f419969491669664891d88 vp90-2-02-size-lf-1920x1080-1920x1080-0174.i420
+d4b993d87c2f4042c0b647e4e50cca38 vp90-2-02-size-lf-1920x1080-1920x1080-0175.i420
+5acb9f10167b208a32babbe56fd07587 vp90-2-02-size-lf-1920x1080-1920x1080-0176.i420
+958900bb713559d272470f1e85cffcda vp90-2-02-size-lf-1920x1080-1920x1080-0177.i420
+f355f1858fd2c8a4932dfd6d6cfe7673 vp90-2-02-size-lf-1920x1080-1920x1080-0178.i420
+45caac733e395f63c82c9d8ab050c858 vp90-2-02-size-lf-1920x1080-1920x1080-0179.i420
+8b05c2c352c4adc5cabc0184a1f510f5 vp90-2-02-size-lf-1920x1080-1920x1080-0180.i420
+167c3fe4df204bab9cceb17ae655aa61 vp90-2-02-size-lf-1920x1080-1920x1080-0181.i420
+3859339e9a63d0e05797f0de535f7be8 vp90-2-02-size-lf-1920x1080-1920x1080-0182.i420
+2d5cc539454cb6aace19ab9bba60b066 vp90-2-02-size-lf-1920x1080-1920x1080-0183.i420
+f51299a0601fb1621d2de6b0e2391a9a vp90-2-02-size-lf-1920x1080-1920x1080-0184.i420
+92b0ed2528c0756b0c84721a306ba61b vp90-2-02-size-lf-1920x1080-1920x1080-0185.i420
+8f1870cce38718b02d0a4e26a5a2619e vp90-2-02-size-lf-1920x1080-1920x1080-0186.i420
+e0ed74a244b8698baaefd837ab1590ff vp90-2-02-size-lf-1920x1080-1920x1080-0187.i420
+c8b10e2ac68bd0106e34a57943f23e12 vp90-2-02-size-lf-1920x1080-1920x1080-0188.i420
+f5e505e3d681763fd447214aed863ab9 vp90-2-02-size-lf-1920x1080-1920x1080-0189.i420
+c2cc70d65ba1c13c5e07a1d28611792a vp90-2-02-size-lf-1920x1080-1920x1080-0190.i420
+e518aac5c551f7c09652c25905cce41f vp90-2-02-size-lf-1920x1080-1920x1080-0191.i420
+66379f7a3b2de153486a76b459e2ce3b vp90-2-02-size-lf-1920x1080-1920x1080-0192.i420
+552afad8181d6d138e2e62c971a10a42 vp90-2-02-size-lf-1920x1080-1920x1080-0193.i420
+ac21d5c2ef3ccaabbaa9f08fcc9d0db8 vp90-2-02-size-lf-1920x1080-1920x1080-0194.i420
+f67af966e3fa79a6fce48b7d9e1fb593 vp90-2-02-size-lf-1920x1080-1920x1080-0195.i420
+dd6331e4361f8b8bd45d571db2e0344b vp90-2-02-size-lf-1920x1080-1920x1080-0196.i420
+14a0db3c0a39b7431c337622ed4078a5 vp90-2-02-size-lf-1920x1080-1920x1080-0197.i420
+8d3394abad260b5e4e24abe4a898cb7b vp90-2-02-size-lf-1920x1080-1920x1080-0198.i420
+e085ce3274d77fa874ab70183353b4c1 vp90-2-02-size-lf-1920x1080-1920x1080-0199.i420
+de083fffb4226ec227d3aa9c873dfcf7 vp90-2-02-size-lf-1920x1080-1920x1080-0200.i420
+4628eff51846a97fb708c4d3753ffee4 vp90-2-02-size-lf-1920x1080-1920x1080-0201.i420
+b480e4409fa8ca9c2e0d4bd57b7e8cf6 vp90-2-02-size-lf-1920x1080-1920x1080-0202.i420
+ff21164cc573b6f79739165b61b68dd0 vp90-2-02-size-lf-1920x1080-1920x1080-0203.i420
+ec391026b77527ed48029adfbd1afc93 vp90-2-02-size-lf-1920x1080-1920x1080-0204.i420
+23186dd93e32603c3709aa3419963ca9 vp90-2-02-size-lf-1920x1080-1920x1080-0205.i420
+6a1968207b37594cc82736f086a0a023 vp90-2-02-size-lf-1920x1080-1920x1080-0206.i420
+57358a332af03e5d96d8c1cd5e4a497d vp90-2-02-size-lf-1920x1080-1920x1080-0207.i420
+584ac2ecc56e1a9f0f1a5356b161a7a6 vp90-2-02-size-lf-1920x1080-1920x1080-0208.i420
+f566d1e385f25ef9b74989cbe7bbca7b vp90-2-02-size-lf-1920x1080-1920x1080-0209.i420
+a4bf059ee8207d1edeebc3193e8db8e0 vp90-2-02-size-lf-1920x1080-1920x1080-0210.i420
+cc5948fa18d6e73afa253eedbfaecd41 vp90-2-02-size-lf-1920x1080-1920x1080-0211.i420
+61d44c8bfca18b6742fed974366898b8 vp90-2-02-size-lf-1920x1080-1920x1080-0212.i420
+c48d67da0d72daaf635226b9e30e05e3 vp90-2-02-size-lf-1920x1080-1920x1080-0213.i420
+b4596a68e708f304875fd2306fec56e9 vp90-2-02-size-lf-1920x1080-1920x1080-0214.i420
+b59be425ebea3d15b4be140e552ab944 vp90-2-02-size-lf-1920x1080-1920x1080-0215.i420
+1e966f137918375ae060d4c49cf38664 vp90-2-02-size-lf-1920x1080-1920x1080-0216.i420
+0ff25f8e98719fd57dc31d391bb930c4 vp90-2-02-size-lf-1920x1080-1920x1080-0217.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_deltaq.vp9 b/tests/tests/media/res/raw/vp90_2_03_deltaq.vp9
new file mode 100644
index 0000000..9033b23
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_deltaq.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_deltaq_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_deltaq_vp9_md5
new file mode 100644
index 0000000..aca350c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_deltaq_vp9_md5
@@ -0,0 +1,2 @@
+2f90d606edc511c8c960530dd915cb98 vp90-2-03-deltaq-352x240-0001.i420
+7fd451a057d6341b2b0d116f59e41a13 vp90-2-03-deltaq-352x240-0002.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x196.vp9
new file mode 100644
index 0000000..06988f1
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x196_vp9_md5
new file mode 100644
index 0000000..847972f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x196_vp9_md5
@@ -0,0 +1,10 @@
+14cc1c34b8106e35238d4650a9123852 vp90-2-03-size-196x196-196x196-0001.i420
+66e0bb9136ea24e30b781a4610b428a1 vp90-2-03-size-196x196-196x196-0002.i420
+8e36679c20a3a3e974fdacf7a9343817 vp90-2-03-size-196x196-196x196-0003.i420
+2669fd03ce7ce01f4fc9db23e06fffdb vp90-2-03-size-196x196-196x196-0004.i420
+46ced29eb6edf2136c8ee19e9a87380f vp90-2-03-size-196x196-196x196-0005.i420
+4e4138b65a30bc56cd18663a1799f98f vp90-2-03-size-196x196-196x196-0006.i420
+580b0431b5f808c67e50ed34e62f39ad vp90-2-03-size-196x196-196x196-0007.i420
+1339bbe256d8499ab17d6a550f7dac70 vp90-2-03-size-196x196-196x196-0008.i420
+89b9dac29a4c4136249c40a3763dc114 vp90-2-03-size-196x196-196x196-0009.i420
+a735d341d7df9dcd0b6e51a82b813f61 vp90-2-03-size-196x196-196x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x198.vp9
new file mode 100644
index 0000000..cffe250
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x198_vp9_md5
new file mode 100644
index 0000000..33056c5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x198_vp9_md5
@@ -0,0 +1,10 @@
+d2bd2dfaf2ac22b3f2499844f228d89a vp90-2-03-size-196x198-196x198-0001.i420
+e066448baeb39da04b22d4d2ebd27b0a vp90-2-03-size-196x198-196x198-0002.i420
+aace53c0ecca2596c51dd5e70da7abc4 vp90-2-03-size-196x198-196x198-0003.i420
+077256d024ab101918d10ae61142f203 vp90-2-03-size-196x198-196x198-0004.i420
+e2bfdad36b0365d41dc6813a371111ee vp90-2-03-size-196x198-196x198-0005.i420
+17495af68b0a2c075899849382f3b046 vp90-2-03-size-196x198-196x198-0006.i420
+7853db163344798e5c37672adaac92d8 vp90-2-03-size-196x198-196x198-0007.i420
+7b2ee2e1ca709c58457c7d818e47c95c vp90-2-03-size-196x198-196x198-0008.i420
+f7eb3ce10561628f932861358a30b414 vp90-2-03-size-196x198-196x198-0009.i420
+3182374f5aa539fd0faa44ed4a7492e5 vp90-2-03-size-196x198-196x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x200.vp9
new file mode 100644
index 0000000..53e2c03
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x200_vp9_md5
new file mode 100644
index 0000000..7746aba
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x200_vp9_md5
@@ -0,0 +1,10 @@
+b2f2ac3e3833ae1b4dd075fe00210373 vp90-2-03-size-196x200-196x200-0001.i420
+c0cce05e56a07111fe62553fa3a87074 vp90-2-03-size-196x200-196x200-0002.i420
+626aab3de03242073e03504e166b4697 vp90-2-03-size-196x200-196x200-0003.i420
+574d2c810f0bbfac57f1f06c2b97445c vp90-2-03-size-196x200-196x200-0004.i420
+7d5bc5860bd1422d08396fe080452099 vp90-2-03-size-196x200-196x200-0005.i420
+5d47bbfb0f5cdecfe8415ca2caddc206 vp90-2-03-size-196x200-196x200-0006.i420
+fbef6a0fa51029d0475975945ccf4b36 vp90-2-03-size-196x200-196x200-0007.i420
+c9179c153bcb2a8e9d17ed04e5e2c39c vp90-2-03-size-196x200-196x200-0008.i420
+107d796592cf2140d4d492beadba2d68 vp90-2-03-size-196x200-196x200-0009.i420
+eee46f9ee67fc1121bffb63aeb7c768f vp90-2-03-size-196x200-196x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x202.vp9
new file mode 100644
index 0000000..87394bd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x202_vp9_md5
new file mode 100644
index 0000000..351cf95
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x202_vp9_md5
@@ -0,0 +1,10 @@
+7109d2ef160828ece26337f36fcfc092 vp90-2-03-size-196x202-196x202-0001.i420
+bdaa6612f81a956d9b20d55a04df8346 vp90-2-03-size-196x202-196x202-0002.i420
+15eb75495d2713a64415b990b058d5ca vp90-2-03-size-196x202-196x202-0003.i420
+b997c84553475ba84e8ba3d7ee19ae4e vp90-2-03-size-196x202-196x202-0004.i420
+63a8badd691bcf643cf676d029ce8a6c vp90-2-03-size-196x202-196x202-0005.i420
+b8ca23d9b3418c4c36040a215b2b7917 vp90-2-03-size-196x202-196x202-0006.i420
+1be0da18386c35e4a5e5d5d32d9a4468 vp90-2-03-size-196x202-196x202-0007.i420
+e75a03fa70fe7e6b3a8d8ce7dc8305f1 vp90-2-03-size-196x202-196x202-0008.i420
+cbd2b60df9209025c8e890771a05321d vp90-2-03-size-196x202-196x202-0009.i420
+c655d6fcc3333917b66358a9ac2b1357 vp90-2-03-size-196x202-196x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x208.vp9
new file mode 100644
index 0000000..d20e7cc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x208_vp9_md5
new file mode 100644
index 0000000..94a9277
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x208_vp9_md5
@@ -0,0 +1,10 @@
+efa2a2a76a0fe709a78e491346cfcf29 vp90-2-03-size-196x208-196x208-0001.i420
+97de85e21b408878853fa870104707d7 vp90-2-03-size-196x208-196x208-0002.i420
+419bd1157e156d3059190d6b561c57dd vp90-2-03-size-196x208-196x208-0003.i420
+fbb6e01c524fc7c8007c6cfe2c64f467 vp90-2-03-size-196x208-196x208-0004.i420
+7453994c2e9901fa23f295ec0b556f9c vp90-2-03-size-196x208-196x208-0005.i420
+ba39dc984789fa2c4b833cd88013cc97 vp90-2-03-size-196x208-196x208-0006.i420
+cea5061cac1be18d5f9a9301a5460491 vp90-2-03-size-196x208-196x208-0007.i420
+1c583018c425b1a91949e0c3eb0a4152 vp90-2-03-size-196x208-196x208-0008.i420
+b48be02280ac6f97731af69bcf18de25 vp90-2-03-size-196x208-196x208-0009.i420
+6f8ab465214d8374c9ff77b939da333e vp90-2-03-size-196x208-196x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x210.vp9
new file mode 100644
index 0000000..c1dfbb3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x210_vp9_md5
new file mode 100644
index 0000000..eddddaf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x210_vp9_md5
@@ -0,0 +1,10 @@
+fccc18714a9ed3840bd6e9c6ca4858e5 vp90-2-03-size-196x210-196x210-0001.i420
+a8f6eb43cf6ed670eb180c5051de06f7 vp90-2-03-size-196x210-196x210-0002.i420
+6a9baf9eae6e799deaefd6e801f7ace3 vp90-2-03-size-196x210-196x210-0003.i420
+3bb44c8a45aab088c9887c11bc6a4acf vp90-2-03-size-196x210-196x210-0004.i420
+0907a7e926be9e54bbb087251b4715d9 vp90-2-03-size-196x210-196x210-0005.i420
+10fef2876c20eb3f9570c0c23e5acc69 vp90-2-03-size-196x210-196x210-0006.i420
+ffe5d2b6d874af0f878075c97940ccfb vp90-2-03-size-196x210-196x210-0007.i420
+d10fae10144ff88075048827203f7e9c vp90-2-03-size-196x210-196x210-0008.i420
+bdf35736ac625f2178902c1f24d513c0 vp90-2-03-size-196x210-196x210-0009.i420
+30882bf2c21785be6234b637c4b16b28 vp90-2-03-size-196x210-196x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x224.vp9
new file mode 100644
index 0000000..605dddf
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x224_vp9_md5
new file mode 100644
index 0000000..18395ce
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x224_vp9_md5
@@ -0,0 +1,10 @@
+13263674ea5aa619250dfd139bda872f vp90-2-03-size-196x224-196x224-0001.i420
+39f5cbd8917f2b3a1df8cf2b786266de vp90-2-03-size-196x224-196x224-0002.i420
+f9aade31f9e3065f3d5b8645ef099ac6 vp90-2-03-size-196x224-196x224-0003.i420
+124f9664380f092e692b5e881f5a8fcc vp90-2-03-size-196x224-196x224-0004.i420
+e8e040e417830f5e911537828ace21b7 vp90-2-03-size-196x224-196x224-0005.i420
+84ce09882b9c184a787e8022e6d8c8de vp90-2-03-size-196x224-196x224-0006.i420
+b1397fd91814e4fdc4f75c89161ced26 vp90-2-03-size-196x224-196x224-0007.i420
+d64f39d64d248f0223ed359e092d46cb vp90-2-03-size-196x224-196x224-0008.i420
+e04ee663dcc52eebd74255671c6f4ec9 vp90-2-03-size-196x224-196x224-0009.i420
+955303cb73bf072c693f37d9778ca2b6 vp90-2-03-size-196x224-196x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_196x226.vp9
new file mode 100644
index 0000000..29f7381
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_196x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_196x226_vp9_md5
new file mode 100644
index 0000000..1c250d6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_196x226_vp9_md5
@@ -0,0 +1,10 @@
+5cb240f10761f59687612ed589759800 vp90-2-03-size-196x226-196x226-0001.i420
+9d8d5b57336ddfa5c9c5100a0302197d vp90-2-03-size-196x226-196x226-0002.i420
+9db74997d23b16f527c63e88795331dc vp90-2-03-size-196x226-196x226-0003.i420
+52758cd901533e790334d464bee516da vp90-2-03-size-196x226-196x226-0004.i420
+40e671b9b85d07b13acba85eb64bbbaa vp90-2-03-size-196x226-196x226-0005.i420
+8524b2cd2c9bb3e41c6167f8269e75d2 vp90-2-03-size-196x226-196x226-0006.i420
+ff194ad6fa180fde86cc05a99c0580ec vp90-2-03-size-196x226-196x226-0007.i420
+22ab303cb37745a73c227cd7d1c70003 vp90-2-03-size-196x226-196x226-0008.i420
+01986c58e82e0b5194418f5b75a8599c vp90-2-03-size-196x226-196x226-0009.i420
+eedfc9c14cbf3fa10402dbed52103848 vp90-2-03-size-196x226-196x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x196.vp9
new file mode 100644
index 0000000..78d6b72
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x196_vp9_md5
new file mode 100644
index 0000000..fc8de27
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x196_vp9_md5
@@ -0,0 +1,10 @@
+c980866a6f17d4107ce128ee112d74cf vp90-2-03-size-198x196-198x196-0001.i420
+d4d5d2a10e73f1d09919355dc4d63d48 vp90-2-03-size-198x196-198x196-0002.i420
+82c76ed020acb68ff9d8bd81899aa6f8 vp90-2-03-size-198x196-198x196-0003.i420
+8330705fa354fb5838af56dcf9cc0980 vp90-2-03-size-198x196-198x196-0004.i420
+e47b63d839a592e6372d18249bf5bc0c vp90-2-03-size-198x196-198x196-0005.i420
+b6095b6f752a50e96cab52e7c3fd52f3 vp90-2-03-size-198x196-198x196-0006.i420
+fc4786f48b6ee31043d94f79c5c8a54f vp90-2-03-size-198x196-198x196-0007.i420
+7d3d06c96496bd5ab44fe5489877771d vp90-2-03-size-198x196-198x196-0008.i420
+5b96de089a9faa2dc01697fe9dd97f7f vp90-2-03-size-198x196-198x196-0009.i420
+d7361203b4c264067dcb7bf6912e8df2 vp90-2-03-size-198x196-198x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x198.vp9
new file mode 100644
index 0000000..b66e0d8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x198_vp9_md5
new file mode 100644
index 0000000..7eae1b0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x198_vp9_md5
@@ -0,0 +1,10 @@
+ee0760611da9938e72f551d219671c76 vp90-2-03-size-198x198-198x198-0001.i420
+c512cb8a864c25318254438c7170f373 vp90-2-03-size-198x198-198x198-0002.i420
+aaea10aeb7dfd1f9f6dc77adccfcd56f vp90-2-03-size-198x198-198x198-0003.i420
+fb4e68ce202d9c6ecbddc6fe50b1cd7b vp90-2-03-size-198x198-198x198-0004.i420
+57a803d02f0d71ec4c3c17a112574525 vp90-2-03-size-198x198-198x198-0005.i420
+526d0beaf7ef721c3a6ae8bf3505fd78 vp90-2-03-size-198x198-198x198-0006.i420
+972ab31f81dbb79c2273bcfc98569e8b vp90-2-03-size-198x198-198x198-0007.i420
+e1f05d62691bd1a9494d57449417415c vp90-2-03-size-198x198-198x198-0008.i420
+bc39a559b25e5a1ac698e0101bd6bf29 vp90-2-03-size-198x198-198x198-0009.i420
+04caed04ac21c76af873e21899860fb2 vp90-2-03-size-198x198-198x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x200.vp9
new file mode 100644
index 0000000..5f6d62e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x200_vp9_md5
new file mode 100644
index 0000000..777aeef
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x200_vp9_md5
@@ -0,0 +1,10 @@
+fb0e8171b0f91d9b2ceb5430db27a67b vp90-2-03-size-198x200-198x200-0001.i420
+73f121e6aa0e6290cfd06ac9b033c772 vp90-2-03-size-198x200-198x200-0002.i420
+4113897efc44f49f5169a579bee03596 vp90-2-03-size-198x200-198x200-0003.i420
+aec1d4cf1a15e12b689980cfe136d5d6 vp90-2-03-size-198x200-198x200-0004.i420
+1322af65f647254330120e67ddae38bd vp90-2-03-size-198x200-198x200-0005.i420
+5d28c1684451812c9db41433e6286d85 vp90-2-03-size-198x200-198x200-0006.i420
+33843fc49d1d8655520c2f42332222ca vp90-2-03-size-198x200-198x200-0007.i420
+92a8125d8c75eaf6159d5f431c5c71bf vp90-2-03-size-198x200-198x200-0008.i420
+5bc96553842f65a3e37f012b72b580f5 vp90-2-03-size-198x200-198x200-0009.i420
+de5eb6299ee5034dc3b01cdc94bf810a vp90-2-03-size-198x200-198x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x202.vp9
new file mode 100644
index 0000000..89f03df
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x202_vp9_md5
new file mode 100644
index 0000000..a5eef00
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x202_vp9_md5
@@ -0,0 +1,10 @@
+f5e1cf4cc56742fadddf42189a3f65e3 vp90-2-03-size-198x202-198x202-0001.i420
+f3e8ca2c8deb29a6b5bfe415b39c901e vp90-2-03-size-198x202-198x202-0002.i420
+89c513049e41e145bca46a7f7119567c vp90-2-03-size-198x202-198x202-0003.i420
+419089035739e84f1aa14ccdf34edcb1 vp90-2-03-size-198x202-198x202-0004.i420
+4962c98c23b16b9257869a8ad5138731 vp90-2-03-size-198x202-198x202-0005.i420
+fde9e858ec895c36c2d8071e69f68db6 vp90-2-03-size-198x202-198x202-0006.i420
+42e1271915f31a00be3627fa866ce3ee vp90-2-03-size-198x202-198x202-0007.i420
+c15f794933f913861a6d0041ff2fccdb vp90-2-03-size-198x202-198x202-0008.i420
+35dab245ba952dc6fddc1a9668c30b28 vp90-2-03-size-198x202-198x202-0009.i420
+30bb4ef77cdde9cf5aea0f1287183b23 vp90-2-03-size-198x202-198x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x208.vp9
new file mode 100644
index 0000000..49eca9f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x208_vp9_md5
new file mode 100644
index 0000000..eccf93d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x208_vp9_md5
@@ -0,0 +1,10 @@
+d45b561f81cbfcca8a1dddbc2bf8ca31 vp90-2-03-size-198x208-198x208-0001.i420
+3664f63b2e59e380622caadb7a05545e vp90-2-03-size-198x208-198x208-0002.i420
+0662fa199512320704efecc10af1aaa4 vp90-2-03-size-198x208-198x208-0003.i420
+d8dc00882e73be89d0585663892cbcff vp90-2-03-size-198x208-198x208-0004.i420
+ff64b8d50b7c5b484a06dab09a26147c vp90-2-03-size-198x208-198x208-0005.i420
+1771b6a55112eb7ea10885d1390339cc vp90-2-03-size-198x208-198x208-0006.i420
+0d5944e8a13e3c2faffb562bbe2671a8 vp90-2-03-size-198x208-198x208-0007.i420
+744bed3a88407b75a8ff27a1b0cec64e vp90-2-03-size-198x208-198x208-0008.i420
+3887415f2ab10d2a265c4a413e7060b9 vp90-2-03-size-198x208-198x208-0009.i420
+7dd683019b19b464bc0436f41e0b7c87 vp90-2-03-size-198x208-198x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x210.vp9
new file mode 100644
index 0000000..97dfd89
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x210_vp9_md5
new file mode 100644
index 0000000..0c19c2f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x210_vp9_md5
@@ -0,0 +1,10 @@
+8525a27170982c059d5904c1af3b43fb vp90-2-03-size-198x210-198x210-0001.i420
+c4eb329733913360384d3917a58f6f36 vp90-2-03-size-198x210-198x210-0002.i420
+ec118b87c9cba0e4bd89fd43567cca4e vp90-2-03-size-198x210-198x210-0003.i420
+7e57c6caba7924823977e2c9bc11f7fa vp90-2-03-size-198x210-198x210-0004.i420
+f77ffb7228a5eda848acc40ff636ecad vp90-2-03-size-198x210-198x210-0005.i420
+c5dddafbe3badcbbcaaebe97076e0394 vp90-2-03-size-198x210-198x210-0006.i420
+34d69ae2e5b4c4fbcc51627237c9abc5 vp90-2-03-size-198x210-198x210-0007.i420
+d9c63fa8b18d6c54e5fa31db866c06cc vp90-2-03-size-198x210-198x210-0008.i420
+7ab392764a399328bf35977539e3148a vp90-2-03-size-198x210-198x210-0009.i420
+7fbb7bae3ec775298aaa49a286dfb9d1 vp90-2-03-size-198x210-198x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x224.vp9
new file mode 100644
index 0000000..360ab98
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x224_vp9_md5
new file mode 100644
index 0000000..12c6979
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x224_vp9_md5
@@ -0,0 +1,10 @@
+5f69230bfd8bb485bd85552b18339fc0 vp90-2-03-size-198x224-198x224-0001.i420
+f5c365774fc1d0bffd5025ce2e931aaf vp90-2-03-size-198x224-198x224-0002.i420
+2898234103c3624e6470ae82c916e000 vp90-2-03-size-198x224-198x224-0003.i420
+d82a7fa705180b68a8ee8cb7de0cdd2d vp90-2-03-size-198x224-198x224-0004.i420
+144a162d418deae62883a2cc4c341b4c vp90-2-03-size-198x224-198x224-0005.i420
+b3419a48385e42ca15717289ff2daa1c vp90-2-03-size-198x224-198x224-0006.i420
+d6306b5737f88f989bf2e6a1084a94fe vp90-2-03-size-198x224-198x224-0007.i420
+5669761d7417b52b3cf81d44a13e3fb7 vp90-2-03-size-198x224-198x224-0008.i420
+3f730b8658d7a6657d1af38c75357512 vp90-2-03-size-198x224-198x224-0009.i420
+27df68d515148f732325bf821037d59f vp90-2-03-size-198x224-198x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_198x226.vp9
new file mode 100644
index 0000000..c4d1a7c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_198x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_198x226_vp9_md5
new file mode 100644
index 0000000..31305ef
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_198x226_vp9_md5
@@ -0,0 +1,10 @@
+412c33a8fd71c99e68e6701b050b107c vp90-2-03-size-198x226-198x226-0001.i420
+8e69483ff8a094096dd550b30be20dde vp90-2-03-size-198x226-198x226-0002.i420
+b8df87ab3d2613be31a3743e34d7e794 vp90-2-03-size-198x226-198x226-0003.i420
+ec4b08a4014950f1fe04e83f8a790af0 vp90-2-03-size-198x226-198x226-0004.i420
+030da2b60627d879730108826ce6632c vp90-2-03-size-198x226-198x226-0005.i420
+03aab0c9b4d75bc0b47fa5237e9efe3d vp90-2-03-size-198x226-198x226-0006.i420
+fd01e369df258f340eb8e486c07ae136 vp90-2-03-size-198x226-198x226-0007.i420
+1c301f0e60c96008fd7b6e8de1ebaa29 vp90-2-03-size-198x226-198x226-0008.i420
+912723f43b2b36366c3e6ab122d31801 vp90-2-03-size-198x226-198x226-0009.i420
+b2774a66f7aa0fb7dd7e64b0d67818cd vp90-2-03-size-198x226-198x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x196.vp9
new file mode 100644
index 0000000..2d8ea87
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x196_vp9_md5
new file mode 100644
index 0000000..0b38c2b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x196_vp9_md5
@@ -0,0 +1,10 @@
+651a0627c6cdaee8b46e1f8c4121a368 vp90-2-03-size-200x196-200x196-0001.i420
+3e63075148df16f69c933cf6c63e078c vp90-2-03-size-200x196-200x196-0002.i420
+edf18e52b7d52af2bb7594ed358542d8 vp90-2-03-size-200x196-200x196-0003.i420
+30284124756d00d10f4f8428206ceab8 vp90-2-03-size-200x196-200x196-0004.i420
+6f6ecde53cd0ea5298f4529d396460c6 vp90-2-03-size-200x196-200x196-0005.i420
+0431d389278957fbef3e72f69f3ce008 vp90-2-03-size-200x196-200x196-0006.i420
+a047c60c4c60d2ea1f79c86dc98cdf8e vp90-2-03-size-200x196-200x196-0007.i420
+dceda8bf128a8cdcadfa6c5db49cde51 vp90-2-03-size-200x196-200x196-0008.i420
+d8a6283637f5abda17e0bf150eac2983 vp90-2-03-size-200x196-200x196-0009.i420
+33dca31ef26fdd0daf9971c8de685d01 vp90-2-03-size-200x196-200x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x198.vp9
new file mode 100644
index 0000000..e910dea6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x198_vp9_md5
new file mode 100644
index 0000000..055811c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x198_vp9_md5
@@ -0,0 +1,10 @@
+d4b3578d800c747bcabaa484a140ffb0 vp90-2-03-size-200x198-200x198-0001.i420
+a40f6f8c384c5dc3d5546d960bb6d9e5 vp90-2-03-size-200x198-200x198-0002.i420
+e270ae8754d9906dd88b1c7d05280801 vp90-2-03-size-200x198-200x198-0003.i420
+bde7fde5012840c5e188f3b29f4f0003 vp90-2-03-size-200x198-200x198-0004.i420
+8f8510c1130615b64fb8469af66ff678 vp90-2-03-size-200x198-200x198-0005.i420
+79b9d4e0c64f82a6e9540394222a593d vp90-2-03-size-200x198-200x198-0006.i420
+34852ac9ca5c6bfa51736296784343c7 vp90-2-03-size-200x198-200x198-0007.i420
+b055218509dbed644113642f8f0ac8a8 vp90-2-03-size-200x198-200x198-0008.i420
+1628866b436f1c4b892474025226e545 vp90-2-03-size-200x198-200x198-0009.i420
+3fdec760c04e30c90e74afb38dbf757c vp90-2-03-size-200x198-200x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x200.vp9
new file mode 100644
index 0000000..039ccef
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x200_vp9_md5
new file mode 100644
index 0000000..b6d78f8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x200_vp9_md5
@@ -0,0 +1,10 @@
+b339f4e563afadb25f43b8c05b12dc03 vp90-2-03-size-200x200-200x200-0001.i420
+3bd5280e7fb42400085b0b1dbba1905e vp90-2-03-size-200x200-200x200-0002.i420
+acf1c84cabff763fe2073d2c1f183bfc vp90-2-03-size-200x200-200x200-0003.i420
+eaa4983b6baf907efb11d137644569d2 vp90-2-03-size-200x200-200x200-0004.i420
+8a1871c8dc38a19dfd4ac571ad7f39be vp90-2-03-size-200x200-200x200-0005.i420
+0be539bd51f5f364828dd0abc70360be vp90-2-03-size-200x200-200x200-0006.i420
+df60622d2c9f294f61d738be9e3bd16c vp90-2-03-size-200x200-200x200-0007.i420
+22b3f1d51ddf92c7d2add305ba0ef405 vp90-2-03-size-200x200-200x200-0008.i420
+01ba29be721e64a5a50526de0797c7d3 vp90-2-03-size-200x200-200x200-0009.i420
+7b7aa7fa0e58202b3104671375762587 vp90-2-03-size-200x200-200x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x202.vp9
new file mode 100644
index 0000000..10ed70e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x202_vp9_md5
new file mode 100644
index 0000000..f93617e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x202_vp9_md5
@@ -0,0 +1,10 @@
+c4a13df44e66f06961dd72fc990439e9 vp90-2-03-size-200x202-200x202-0001.i420
+81c73b8d3806ad96af8f422914a253f8 vp90-2-03-size-200x202-200x202-0002.i420
+05f77526125e802be9cb306e375ded6e vp90-2-03-size-200x202-200x202-0003.i420
+ab2e224840ff89abec2c675a23a73094 vp90-2-03-size-200x202-200x202-0004.i420
+c30f58f88819eb57102678b169e15188 vp90-2-03-size-200x202-200x202-0005.i420
+33e5e2799eb4a9c548c8372fd6769db9 vp90-2-03-size-200x202-200x202-0006.i420
+fa53c1c7e60bd1d00335af542ec69ed7 vp90-2-03-size-200x202-200x202-0007.i420
+534cafe658af10a314d6d084e55b3620 vp90-2-03-size-200x202-200x202-0008.i420
+502529e4fbecc8b890abf665fa21f53c vp90-2-03-size-200x202-200x202-0009.i420
+bf1f73c6e77370bc51a770c8ae87bd12 vp90-2-03-size-200x202-200x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x208.vp9
new file mode 100644
index 0000000..a78b114
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x208_vp9_md5
new file mode 100644
index 0000000..4611a4a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x208_vp9_md5
@@ -0,0 +1,10 @@
+702748bec18c500dd41d93ae74b11d56 vp90-2-03-size-200x208-200x208-0001.i420
+4fb542190dab2fd673724d47451ff6ee vp90-2-03-size-200x208-200x208-0002.i420
+dbb4d27d52797dab67e39d32092c9d44 vp90-2-03-size-200x208-200x208-0003.i420
+e4a0ed1572207b7ba433896bba711148 vp90-2-03-size-200x208-200x208-0004.i420
+28ec32bc165f4f9d455efec8a7aa8737 vp90-2-03-size-200x208-200x208-0005.i420
+a95910575a6423abffb28ca38c384b34 vp90-2-03-size-200x208-200x208-0006.i420
+791f1c558c5467725f4614a75a8a687e vp90-2-03-size-200x208-200x208-0007.i420
+cfd3e12f84f7a811966721e890228313 vp90-2-03-size-200x208-200x208-0008.i420
+824c5fdf938551c28ac1c996645ae52f vp90-2-03-size-200x208-200x208-0009.i420
+7465917fdd0206e393968232a0ec5193 vp90-2-03-size-200x208-200x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x210.vp9
new file mode 100644
index 0000000..27a3f40
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x210_vp9_md5
new file mode 100644
index 0000000..75c190c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x210_vp9_md5
@@ -0,0 +1,10 @@
+31ef44bd12ae702f306c55eba10d2ba7 vp90-2-03-size-200x210-200x210-0001.i420
+83e9d913f5aa058d79a81047ca45e4a2 vp90-2-03-size-200x210-200x210-0002.i420
+b5e21313b859f1e2c67aaac5fefc9f68 vp90-2-03-size-200x210-200x210-0003.i420
+959d63c1b219c3479af673a9a8b8d82c vp90-2-03-size-200x210-200x210-0004.i420
+ffcfaf42b69c7cd92f6e3c21987ff7df vp90-2-03-size-200x210-200x210-0005.i420
+e9667d3ee4d8179da44de4fbffcb7df2 vp90-2-03-size-200x210-200x210-0006.i420
+5e2c841bcf4ec6f3a05020d36986fe5b vp90-2-03-size-200x210-200x210-0007.i420
+19fe287c30bd4c90b00a9631409568c0 vp90-2-03-size-200x210-200x210-0008.i420
+58a8843e50b19860a0a91e1e1bb63bfd vp90-2-03-size-200x210-200x210-0009.i420
+0ebd31e18597a567f96645acbb2500cf vp90-2-03-size-200x210-200x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x224.vp9
new file mode 100644
index 0000000..61d8df6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x224_vp9_md5
new file mode 100644
index 0000000..0f64dfc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x224_vp9_md5
@@ -0,0 +1,10 @@
+315d69847bf752a84231a368278eb0b6 vp90-2-03-size-200x224-200x224-0001.i420
+d245738f8627fc345ab38a547bc7d352 vp90-2-03-size-200x224-200x224-0002.i420
+982681cdca448919c2eead94435772ad vp90-2-03-size-200x224-200x224-0003.i420
+7b67b2d96476e17cd407bbccb19fd070 vp90-2-03-size-200x224-200x224-0004.i420
+c38dde73ca097049d1fc689e18a49b5d vp90-2-03-size-200x224-200x224-0005.i420
+525f323b81d780c669a03655bb0d0b56 vp90-2-03-size-200x224-200x224-0006.i420
+5dbeb96f65e383771c1c877ec559044a vp90-2-03-size-200x224-200x224-0007.i420
+7d96e976265ef0f9faf173376caaa9e9 vp90-2-03-size-200x224-200x224-0008.i420
+6047c805a724701b80a133486aae0e65 vp90-2-03-size-200x224-200x224-0009.i420
+eb8895dd994076a52aa3a0c1758ccbb7 vp90-2-03-size-200x224-200x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_200x226.vp9
new file mode 100644
index 0000000..cc08073
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_200x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_200x226_vp9_md5
new file mode 100644
index 0000000..42f870c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_200x226_vp9_md5
@@ -0,0 +1,10 @@
+e45b6b9dce4a8509b7d26bc3cfdf7c86 vp90-2-03-size-200x226-200x226-0001.i420
+ddb9d5033ecfa2d6e9a5505dce374bda vp90-2-03-size-200x226-200x226-0002.i420
+52c495d3137143e0bce9382fe5506057 vp90-2-03-size-200x226-200x226-0003.i420
+d09f3d6ad084f2966196acd48246f951 vp90-2-03-size-200x226-200x226-0004.i420
+1556d006d0119a3172b98a500b27f8d0 vp90-2-03-size-200x226-200x226-0005.i420
+904f86cfbcc3fa683d3d7744a286cd88 vp90-2-03-size-200x226-200x226-0006.i420
+b35907456b8ccab0ae8efc8405b04c89 vp90-2-03-size-200x226-200x226-0007.i420
+b7f2648fe0f873f7e9ea4a6d913e45ec vp90-2-03-size-200x226-200x226-0008.i420
+2da76544bc7e295486c335e17047e12e vp90-2-03-size-200x226-200x226-0009.i420
+10fd6424caf837d37564ef15f1c6f93d vp90-2-03-size-200x226-200x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x196.vp9
new file mode 100644
index 0000000..5961c56
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x196_vp9_md5
new file mode 100644
index 0000000..1e76804
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x196_vp9_md5
@@ -0,0 +1,10 @@
+1261466179df96099e598e46c50fa7c1 vp90-2-03-size-202x196-202x196-0001.i420
+cc0fe373cd0399cf0c95edf92d9ab01f vp90-2-03-size-202x196-202x196-0002.i420
+7a2dc0afd06ecfcf54321fb759f57601 vp90-2-03-size-202x196-202x196-0003.i420
+db9c138503d27f87449f870ab07cab03 vp90-2-03-size-202x196-202x196-0004.i420
+ddea2e5e2659e97132a537566d5ed989 vp90-2-03-size-202x196-202x196-0005.i420
+c31e90b5eee032526c4e0603332fd160 vp90-2-03-size-202x196-202x196-0006.i420
+7e5b40f03b905d9ee749d3097a484ea0 vp90-2-03-size-202x196-202x196-0007.i420
+93e9f7defa94ff03c041448ae1e55cea vp90-2-03-size-202x196-202x196-0008.i420
+aef8e03f0146699faa16ec28dea49dbe vp90-2-03-size-202x196-202x196-0009.i420
+a651d949b4c8f0e455c6592dc98385f7 vp90-2-03-size-202x196-202x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x198.vp9
new file mode 100644
index 0000000..de8d042
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x198_vp9_md5
new file mode 100644
index 0000000..fa76001
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x198_vp9_md5
@@ -0,0 +1,10 @@
+181edc4ebeeff7f0527b93b84d5d8efb vp90-2-03-size-202x198-202x198-0001.i420
+132c71b634fb67eed51fcdef1775b6b2 vp90-2-03-size-202x198-202x198-0002.i420
+fd41144770765fc893adc5843ebe32e4 vp90-2-03-size-202x198-202x198-0003.i420
+77dcbaea101142940b6a78a271842829 vp90-2-03-size-202x198-202x198-0004.i420
+01737c38c1ac711a9744256788211177 vp90-2-03-size-202x198-202x198-0005.i420
+31cd0b5f621daac309c6f249f4c26cd8 vp90-2-03-size-202x198-202x198-0006.i420
+e06d34e570dc46904fdb9eeb55811464 vp90-2-03-size-202x198-202x198-0007.i420
+71bf55030373bde1eaeb52d1e97bfa4a vp90-2-03-size-202x198-202x198-0008.i420
+e96063ff02e8a23a666222b59391de9c vp90-2-03-size-202x198-202x198-0009.i420
+5aa0079168ab5069e8a3064f9e2a6d8b vp90-2-03-size-202x198-202x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x200.vp9
new file mode 100644
index 0000000..79ec044
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x200_vp9_md5
new file mode 100644
index 0000000..1e7817e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x200_vp9_md5
@@ -0,0 +1,10 @@
+20c41d4a1271183dbbc7a44e6b90ea80 vp90-2-03-size-202x200-202x200-0001.i420
+bd8c1fba8d8742f4d98b7d5097c8c828 vp90-2-03-size-202x200-202x200-0002.i420
+55cbe06a925009c1b1f9b609b60b4c1d vp90-2-03-size-202x200-202x200-0003.i420
+78e80c7cf1f142e2dda1bc269b5b3e00 vp90-2-03-size-202x200-202x200-0004.i420
+42ee8157a4c8af6670b81e9324b251e9 vp90-2-03-size-202x200-202x200-0005.i420
+022bdf5a2e1ea5f98503cd25b383ae53 vp90-2-03-size-202x200-202x200-0006.i420
+c2073865386a991da01966878ce1ce6d vp90-2-03-size-202x200-202x200-0007.i420
+6a5b95cd4eff0836b9180a25f663d36a vp90-2-03-size-202x200-202x200-0008.i420
+5e5498c357340d4755dc98eb0669f103 vp90-2-03-size-202x200-202x200-0009.i420
+0907d5e4020111b1ecfe707df71bcd8a vp90-2-03-size-202x200-202x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x202.vp9
new file mode 100644
index 0000000..27a554c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x202_vp9_md5
new file mode 100644
index 0000000..f5ef776
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x202_vp9_md5
@@ -0,0 +1,10 @@
+610cef52d35e9c641f2b8c10489c3d12 vp90-2-03-size-202x202-202x202-0001.i420
+1f84062e607d4798b0544739fe0da99c vp90-2-03-size-202x202-202x202-0002.i420
+ea379947b5c52ea3989dfc3f47c729d9 vp90-2-03-size-202x202-202x202-0003.i420
+1d06b72f06178cbb6bb5d188d22bff43 vp90-2-03-size-202x202-202x202-0004.i420
+25bd41bd7607f88a01aa0cdc336c9975 vp90-2-03-size-202x202-202x202-0005.i420
+86836a95a7a9fb1eefb20f7c5a15a9ab vp90-2-03-size-202x202-202x202-0006.i420
+d8eb3fecce1b646b9877cd4fcca9f9bf vp90-2-03-size-202x202-202x202-0007.i420
+a057e0b29e4ac9717452cc478c418c12 vp90-2-03-size-202x202-202x202-0008.i420
+9a3bab91b4f0fff174536b1609c9632c vp90-2-03-size-202x202-202x202-0009.i420
+d1cd93975f746b6cae490aae31f89e7e vp90-2-03-size-202x202-202x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x208.vp9
new file mode 100644
index 0000000..3a532a0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x208_vp9_md5
new file mode 100644
index 0000000..7eae1c8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x208_vp9_md5
@@ -0,0 +1,10 @@
+d2128e290be81bb0700ebe19e3faed4f vp90-2-03-size-202x208-202x208-0001.i420
+dccaecb7e4ddb7e4224221a659af2a43 vp90-2-03-size-202x208-202x208-0002.i420
+be8e0966aaf3a9fe9164f63695dc3b62 vp90-2-03-size-202x208-202x208-0003.i420
+da944fadc3a239c2254678cadb4cf7fa vp90-2-03-size-202x208-202x208-0004.i420
+3c270f3c02fcbd192b7f896f3f9ee6d9 vp90-2-03-size-202x208-202x208-0005.i420
+0b3ccda0a87c37e40104ae2f1060e8e9 vp90-2-03-size-202x208-202x208-0006.i420
+254253aba91758f302e7177e614596be vp90-2-03-size-202x208-202x208-0007.i420
+b1501a4e372a5249e74aab77e57a28f1 vp90-2-03-size-202x208-202x208-0008.i420
+c4497fea1cefed5cf2b2908620153d26 vp90-2-03-size-202x208-202x208-0009.i420
+5ba20dfa2400b15b5394f315c5c3707d vp90-2-03-size-202x208-202x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x210.vp9
new file mode 100644
index 0000000..69c00a0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x210_vp9_md5
new file mode 100644
index 0000000..3d0ee16
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x210_vp9_md5
@@ -0,0 +1,10 @@
+e4663a28cabbfdd3815efda2d38debcc vp90-2-03-size-202x210-202x210-0001.i420
+3cc7dbec64e9f697f40d740a72c09fc7 vp90-2-03-size-202x210-202x210-0002.i420
+f108981e0ce9c6c501b9ac61d0f1ba44 vp90-2-03-size-202x210-202x210-0003.i420
+63191c7aceb8ac6b030cc1a4b3cda18c vp90-2-03-size-202x210-202x210-0004.i420
+b0a527ae3aafe94d13573199c6f4944f vp90-2-03-size-202x210-202x210-0005.i420
+1be14b213ebf1d653468b8c16bae03fb vp90-2-03-size-202x210-202x210-0006.i420
+44e5a8333a043cd93b9d1cc78e5f188f vp90-2-03-size-202x210-202x210-0007.i420
+bfd7619f990f20e23b47d0738a6a8449 vp90-2-03-size-202x210-202x210-0008.i420
+800405f45ca5198014ef8d8521b044fa vp90-2-03-size-202x210-202x210-0009.i420
+dca4eda872349708f54486433efc8225 vp90-2-03-size-202x210-202x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x224.vp9
new file mode 100644
index 0000000..9e24686
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x224_vp9_md5
new file mode 100644
index 0000000..50b423d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x224_vp9_md5
@@ -0,0 +1,10 @@
+1d318f05310f6d40646f23c62c7eafe4 vp90-2-03-size-202x224-202x224-0001.i420
+42870bd73e1a0c5d84b986db3d24f0f0 vp90-2-03-size-202x224-202x224-0002.i420
+afaac676150286143c6fec7992a81467 vp90-2-03-size-202x224-202x224-0003.i420
+128f84400c272628e802c2369b6bf548 vp90-2-03-size-202x224-202x224-0004.i420
+9adc24d69f12349d8b17c84f5c111767 vp90-2-03-size-202x224-202x224-0005.i420
+b33d2f7a1955248652701f2ade8ab55d vp90-2-03-size-202x224-202x224-0006.i420
+b8acc23721097fce6c8835f5fcfaa6ee vp90-2-03-size-202x224-202x224-0007.i420
+b63bf9a08e4dc5879bbd91efaec95960 vp90-2-03-size-202x224-202x224-0008.i420
+96e8fe29935266f6bd486b99f917eabc vp90-2-03-size-202x224-202x224-0009.i420
+54be14f8dde6857867cd4581f8557044 vp90-2-03-size-202x224-202x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_202x226.vp9
new file mode 100644
index 0000000..eff9809
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_202x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_202x226_vp9_md5
new file mode 100644
index 0000000..88d3400
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_202x226_vp9_md5
@@ -0,0 +1,10 @@
+5aa0f439c58c6335cd86d4238a8c4b68 vp90-2-03-size-202x226-202x226-0001.i420
+3616cc306ec05f89d9b0db63200e4abf vp90-2-03-size-202x226-202x226-0002.i420
+424e98f8ec0ebf2a326a917ee0159bbe vp90-2-03-size-202x226-202x226-0003.i420
+ed5710e412f056fa8c1a277d86dd45d7 vp90-2-03-size-202x226-202x226-0004.i420
+760b850feab485f0bda6cde9943102bc vp90-2-03-size-202x226-202x226-0005.i420
+f4bd90ca72aa707f9b68e6192ac230fd vp90-2-03-size-202x226-202x226-0006.i420
+58e4aad0bc2a9f3fc279df10208bd6f6 vp90-2-03-size-202x226-202x226-0007.i420
+b42f84723dd167d5c544d539275ad537 vp90-2-03-size-202x226-202x226-0008.i420
+5f54feca21331646e68797380260932a vp90-2-03-size-202x226-202x226-0009.i420
+8e787dd318024aff25af8b4d85040f3c vp90-2-03-size-202x226-202x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x196.vp9
new file mode 100644
index 0000000..6f6807f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x196_vp9_md5
new file mode 100644
index 0000000..f32709e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x196_vp9_md5
@@ -0,0 +1,10 @@
+6195975181969789e101a83a555d13f7 vp90-2-03-size-208x196-208x196-0001.i420
+2aca5e3307d68a5e969564a943b8e723 vp90-2-03-size-208x196-208x196-0002.i420
+aee4b00472ee0b6b7a13e31069181db4 vp90-2-03-size-208x196-208x196-0003.i420
+7808595b650a7c14d8a4800db7c014e0 vp90-2-03-size-208x196-208x196-0004.i420
+746eb763b176286aa875ae06b81118c4 vp90-2-03-size-208x196-208x196-0005.i420
+0e8a78ec061319e27d49ca25e333e017 vp90-2-03-size-208x196-208x196-0006.i420
+ac4432db2bb0971d5f70a7dda1210c19 vp90-2-03-size-208x196-208x196-0007.i420
+78870f4bd767f8ab65d369a5b322735d vp90-2-03-size-208x196-208x196-0008.i420
+eee9ddd91209348a64259db6a4a3f80c vp90-2-03-size-208x196-208x196-0009.i420
+c48d21e36a9c0d0d1c64db3f776b3002 vp90-2-03-size-208x196-208x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x198.vp9
new file mode 100644
index 0000000..d6bea55
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x198_vp9_md5
new file mode 100644
index 0000000..a57dc44
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x198_vp9_md5
@@ -0,0 +1,10 @@
+1f1fa3cdf865d8c75183f4ba6203b675 vp90-2-03-size-208x198-208x198-0001.i420
+ead33ead8fea5bd5d831a79f4c75a590 vp90-2-03-size-208x198-208x198-0002.i420
+9a406b4464989fd4bb7cbcb1b18aeaa7 vp90-2-03-size-208x198-208x198-0003.i420
+fab3d228e7032f2cdc440dbfcb17c4c1 vp90-2-03-size-208x198-208x198-0004.i420
+f2f3f8b8d9ece21c359c89245157c613 vp90-2-03-size-208x198-208x198-0005.i420
+321f5a8ecb2cec1780013fe72c237bde vp90-2-03-size-208x198-208x198-0006.i420
+6f025b1f4ef61d261f05ca149a9470e6 vp90-2-03-size-208x198-208x198-0007.i420
+85abcc8d8e6b5f286ed6aa6c588cf416 vp90-2-03-size-208x198-208x198-0008.i420
+b28d710dd44389f774aa02edd6327d5c vp90-2-03-size-208x198-208x198-0009.i420
+79374bef9819eecafa7396d70c80be7f vp90-2-03-size-208x198-208x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x200.vp9
new file mode 100644
index 0000000..40aebf2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x200_vp9_md5
new file mode 100644
index 0000000..35756a2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x200_vp9_md5
@@ -0,0 +1,10 @@
+ff2dda3ddbe8b461d960baba0ad132bf vp90-2-03-size-208x200-208x200-0001.i420
+d6935ac8f2250316f498e8f01afa04fd vp90-2-03-size-208x200-208x200-0002.i420
+57173ebaef7b21698c62fa959cb40ead vp90-2-03-size-208x200-208x200-0003.i420
+f354c76d7cf45e9f3adfdde0f6b3b5c9 vp90-2-03-size-208x200-208x200-0004.i420
+fbc968ecd214b01509a76996e45dd09a vp90-2-03-size-208x200-208x200-0005.i420
+9c314b51a80f2a081adf9b9cc26f5f8a vp90-2-03-size-208x200-208x200-0006.i420
+f22883a6a5b74ffa4bb16f22d496b5a5 vp90-2-03-size-208x200-208x200-0007.i420
+eb4fa914fc5658d43e32c48a0c39bab3 vp90-2-03-size-208x200-208x200-0008.i420
+d763c0c2f44b68e1e3fe9e165334eb0b vp90-2-03-size-208x200-208x200-0009.i420
+344e1075a48cd61e79b0550809b4c91f vp90-2-03-size-208x200-208x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x202.vp9
new file mode 100644
index 0000000..eb6c574
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x202_vp9_md5
new file mode 100644
index 0000000..cd27e7c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x202_vp9_md5
@@ -0,0 +1,10 @@
+e5164f87feadf4b65257f578affc3e04 vp90-2-03-size-208x202-208x202-0001.i420
+6aee5a3b6c3a096dfc1594762b2b248f vp90-2-03-size-208x202-208x202-0002.i420
+cb1c9dce6fdf7372e0eb2397251f0ade vp90-2-03-size-208x202-208x202-0003.i420
+4fe5f24c08690c966b6a14ac3422510b vp90-2-03-size-208x202-208x202-0004.i420
+b22a273814523251b365f3278d8a3a9c vp90-2-03-size-208x202-208x202-0005.i420
+190d9dff373023a25427fc859545ea24 vp90-2-03-size-208x202-208x202-0006.i420
+a6307f38718ed686cb195e3833ab27ab vp90-2-03-size-208x202-208x202-0007.i420
+79630bec5a91d69aca42a910413c2800 vp90-2-03-size-208x202-208x202-0008.i420
+2231cec9c03714b8671e5e1456b148c9 vp90-2-03-size-208x202-208x202-0009.i420
+278458f6734a24f2eb9bc877a6e9d7df vp90-2-03-size-208x202-208x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x208.vp9
new file mode 100644
index 0000000..16612c0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x208_vp9_md5
new file mode 100644
index 0000000..921cbdd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x208_vp9_md5
@@ -0,0 +1,10 @@
+6bff7c1f4c5ef8412ebf669852c70de6 vp90-2-03-size-208x208-208x208-0001.i420
+fdfd7a2308de9509a41fed2880a8f0f5 vp90-2-03-size-208x208-208x208-0002.i420
+d8b464811e9c3b8a6db9cc277ac88c59 vp90-2-03-size-208x208-208x208-0003.i420
+b8fa29e79be3126dd74310d6dd09c747 vp90-2-03-size-208x208-208x208-0004.i420
+dad29803fed686887a0873eb78a469c6 vp90-2-03-size-208x208-208x208-0005.i420
+684de29bbf800f52aea4af9850bcc5b3 vp90-2-03-size-208x208-208x208-0006.i420
+06862dbce7571b4487766b179a596e1d vp90-2-03-size-208x208-208x208-0007.i420
+99582a966bc7070112e214ce7912e485 vp90-2-03-size-208x208-208x208-0008.i420
+a61158581a5719cb0cf13fb3301cb8c4 vp90-2-03-size-208x208-208x208-0009.i420
+9c2295332f34fee3a249262c8ba843bc vp90-2-03-size-208x208-208x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x210.vp9
new file mode 100644
index 0000000..dfec3e8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x210_vp9_md5
new file mode 100644
index 0000000..ab5c7d8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x210_vp9_md5
@@ -0,0 +1,10 @@
+b15c7e98ddd137237b062cb51667522f vp90-2-03-size-208x210-208x210-0001.i420
+00c594c68b19ef39a79a38e86853dc64 vp90-2-03-size-208x210-208x210-0002.i420
+e6742abe3d2c178af4298e121391c299 vp90-2-03-size-208x210-208x210-0003.i420
+efe5387b38c32f1c25c0fc9836921074 vp90-2-03-size-208x210-208x210-0004.i420
+e0e696f4c18af09a74e052903db1468c vp90-2-03-size-208x210-208x210-0005.i420
+f1960270c6704ca47caed63161716025 vp90-2-03-size-208x210-208x210-0006.i420
+a1542d7749cfa447481acd7835db838a vp90-2-03-size-208x210-208x210-0007.i420
+a91fb10a17d1d056667860cc43c81dae vp90-2-03-size-208x210-208x210-0008.i420
+b673bfbb722522b4e7b5e9c5b85cc31f vp90-2-03-size-208x210-208x210-0009.i420
+8b4bb57d3cf609cbf9564a96a6ca6ade vp90-2-03-size-208x210-208x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x224.vp9
new file mode 100644
index 0000000..b60fb5d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x224_vp9_md5
new file mode 100644
index 0000000..bcb9657
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x224_vp9_md5
@@ -0,0 +1,10 @@
+479d07bb96905ad7d5f0ec3ee12b41ba vp90-2-03-size-208x224-208x224-0001.i420
+4b6555aaed8e5a45879773f1bf87962e vp90-2-03-size-208x224-208x224-0002.i420
+c5f42cb796dd7b6622957016ca6b502f vp90-2-03-size-208x224-208x224-0003.i420
+f06c954483560866fbff10bae7ba0785 vp90-2-03-size-208x224-208x224-0004.i420
+af83aff39999852310395fe241ccb49b vp90-2-03-size-208x224-208x224-0005.i420
+108377d6f30ceba6f2377330af2da38f vp90-2-03-size-208x224-208x224-0006.i420
+e81e6e0b37a7b92368ede9cab124567c vp90-2-03-size-208x224-208x224-0007.i420
+59dbe51caaed8e6e825c78c5901fb22c vp90-2-03-size-208x224-208x224-0008.i420
+24686123ea14c8d1a9b447733df0aaab vp90-2-03-size-208x224-208x224-0009.i420
+ce2035c49237c8076f8dac0d3f61848e vp90-2-03-size-208x224-208x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_208x226.vp9
new file mode 100644
index 0000000..4541cf9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_208x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_208x226_vp9_md5
new file mode 100644
index 0000000..e0a7e53
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_208x226_vp9_md5
@@ -0,0 +1,10 @@
+33aa4af6153570518c59960a0c959053 vp90-2-03-size-208x226-208x226-0001.i420
+024fa27dee80ad199528052aaa8d42c7 vp90-2-03-size-208x226-208x226-0002.i420
+b949ef118c7e7e62a8b88e2308219ef9 vp90-2-03-size-208x226-208x226-0003.i420
+3061ee13696ced5e10a646fdd5ca6c34 vp90-2-03-size-208x226-208x226-0004.i420
+c4984bd53dcb7b9e2570f2965d077b2f vp90-2-03-size-208x226-208x226-0005.i420
+d564c35c5caadcfd9f80377fa414af72 vp90-2-03-size-208x226-208x226-0006.i420
+9b7d7b10ee2f3eb7a9ffddcebff45b97 vp90-2-03-size-208x226-208x226-0007.i420
+a0ede7085b04cbb3519d56b2e4347d14 vp90-2-03-size-208x226-208x226-0008.i420
+63d7af745f9e6a34b618db28fe878ffd vp90-2-03-size-208x226-208x226-0009.i420
+85077809087e7bdfb9215bfcd1f1bbc0 vp90-2-03-size-208x226-208x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x196.vp9
new file mode 100644
index 0000000..a5eca1f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x196_vp9_md5
new file mode 100644
index 0000000..c23a9af
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x196_vp9_md5
@@ -0,0 +1,10 @@
+5c69f80da667bfd20394995e93e4cd2b vp90-2-03-size-210x196-210x196-0001.i420
+13363cd8e52ca8c1053db1c84c111bc9 vp90-2-03-size-210x196-210x196-0002.i420
+108976afdf99f59276d6f89879e3bdc3 vp90-2-03-size-210x196-210x196-0003.i420
+770ce25985e6b479d52a9185876cfe83 vp90-2-03-size-210x196-210x196-0004.i420
+eba7cbb3c91989aa4c13487ed01675b5 vp90-2-03-size-210x196-210x196-0005.i420
+f391c30a47c33a250dd20cb12f0a6e01 vp90-2-03-size-210x196-210x196-0006.i420
+c38e12de302177d19dd744a3ea227e90 vp90-2-03-size-210x196-210x196-0007.i420
+8c9370439a0b7289919c6ee68e00570f vp90-2-03-size-210x196-210x196-0008.i420
+ac3748c4b99c4f1aba7430ae12c19cfd vp90-2-03-size-210x196-210x196-0009.i420
+e5228dc84f7933ccc9306907d737ad3c vp90-2-03-size-210x196-210x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x198.vp9
new file mode 100644
index 0000000..b11e214
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x198_vp9_md5
new file mode 100644
index 0000000..7776c06
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x198_vp9_md5
@@ -0,0 +1,10 @@
+d83ee2413e701ae405a2b74863d4c5a9 vp90-2-03-size-210x198-210x198-0001.i420
+f2ebc0f7dc171e0e5d2911c7ee2df5e1 vp90-2-03-size-210x198-210x198-0002.i420
+e189ef4d8add227352a0d6ee62748ee7 vp90-2-03-size-210x198-210x198-0003.i420
+6dcb1dca1a0e2ba85034aba9f021427e vp90-2-03-size-210x198-210x198-0004.i420
+e98c633ba8912f6d65374055ec9af543 vp90-2-03-size-210x198-210x198-0005.i420
+82111cb7d5addce16d9bcba9e0a99503 vp90-2-03-size-210x198-210x198-0006.i420
+bbbc73002f794ab0261fe384b2524226 vp90-2-03-size-210x198-210x198-0007.i420
+0bcdc427df47123959f7de9c44fe291e vp90-2-03-size-210x198-210x198-0008.i420
+505776b3d82e38612393d60b6aa55c1d vp90-2-03-size-210x198-210x198-0009.i420
+feb93758242b847f3d53bb4c97b0ad9c vp90-2-03-size-210x198-210x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x200.vp9
new file mode 100644
index 0000000..93ace8c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x200_vp9_md5
new file mode 100644
index 0000000..20dea3f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x200_vp9_md5
@@ -0,0 +1,10 @@
+2465560246c1ee24d937cb9cbc1422f1 vp90-2-03-size-210x200-210x200-0001.i420
+8926b628dcdf2182516822c7d0d778ec vp90-2-03-size-210x200-210x200-0002.i420
+9bd14d3ebc7fe81c4223116de1b9c2ec vp90-2-03-size-210x200-210x200-0003.i420
+2d029d8461c20236066c0786950540fb vp90-2-03-size-210x200-210x200-0004.i420
+39412b6e62de43bd40c58d4e2e38daf8 vp90-2-03-size-210x200-210x200-0005.i420
+3ea211c24f606b29582147bf872994dd vp90-2-03-size-210x200-210x200-0006.i420
+261c37f88bf7f40549642578d9464aeb vp90-2-03-size-210x200-210x200-0007.i420
+98551d44de1e23165e05975babb72446 vp90-2-03-size-210x200-210x200-0008.i420
+1d85ad052dd27e7e6bfea5d2babf5176 vp90-2-03-size-210x200-210x200-0009.i420
+ad18b6a3698a3674c2488f927810eb0d vp90-2-03-size-210x200-210x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x202.vp9
new file mode 100644
index 0000000..e84b816
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x202_vp9_md5
new file mode 100644
index 0000000..8d7e06e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x202_vp9_md5
@@ -0,0 +1,10 @@
+5d01848aee2b324f2e356627f9c39532 vp90-2-03-size-210x202-210x202-0001.i420
+b671fe34bc0e5a682baff929d26ea627 vp90-2-03-size-210x202-210x202-0002.i420
+e9a40f87ca5aaa5af9772e286feb9063 vp90-2-03-size-210x202-210x202-0003.i420
+4730f60d4c856e8ad877c0d8b1729ec4 vp90-2-03-size-210x202-210x202-0004.i420
+317fc01349e0984c23d15f97a3a0f442 vp90-2-03-size-210x202-210x202-0005.i420
+aea89116ffe48340d1752d1ad5195529 vp90-2-03-size-210x202-210x202-0006.i420
+14694ba65b6308e5f5571486b62ca1cc vp90-2-03-size-210x202-210x202-0007.i420
+53c6102d877c9a30eaa20ddc45207ea0 vp90-2-03-size-210x202-210x202-0008.i420
+7d1e898b1bead878224e8ff15d624bd9 vp90-2-03-size-210x202-210x202-0009.i420
+37b684bfae5dbd33e8dbb8332b94ce8a vp90-2-03-size-210x202-210x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x208.vp9
new file mode 100644
index 0000000..c69fb3f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x208_vp9_md5
new file mode 100644
index 0000000..72f9259
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x208_vp9_md5
@@ -0,0 +1,10 @@
+1156d318c00d299cf5bdc7e485966dab vp90-2-03-size-210x208-210x208-0001.i420
+a8094f8f1e7e04e54251bee8c4c800ce vp90-2-03-size-210x208-210x208-0002.i420
+e2a07d99ffe1cfe6b9fce36e93677fe1 vp90-2-03-size-210x208-210x208-0003.i420
+63d179b00816dbad75b778d2c23955c6 vp90-2-03-size-210x208-210x208-0004.i420
+407de5fb2dfdd52e6173905b09ff22f2 vp90-2-03-size-210x208-210x208-0005.i420
+36900199c56310e651723de4e3ad2f2c vp90-2-03-size-210x208-210x208-0006.i420
+908db56e975b5db07af17fdc51b12be8 vp90-2-03-size-210x208-210x208-0007.i420
+400e32490b1262009a481cc331a00e44 vp90-2-03-size-210x208-210x208-0008.i420
+dc43b786cba033cc92b9921d12f7b3d7 vp90-2-03-size-210x208-210x208-0009.i420
+e8c94c5965c729f5d1ef3ba4509c97c8 vp90-2-03-size-210x208-210x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x210.vp9
new file mode 100644
index 0000000..ad6e896
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x210_vp9_md5
new file mode 100644
index 0000000..6b88d01
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x210_vp9_md5
@@ -0,0 +1,10 @@
+b65725c68978bdaaafdf735dfbafa9e3 vp90-2-03-size-210x210-210x210-0001.i420
+35be2f16bd5dedc9d3f7a016f0d71701 vp90-2-03-size-210x210-210x210-0002.i420
+8c2873a97b51510d7449869e24a348f5 vp90-2-03-size-210x210-210x210-0003.i420
+724a30e8ae539e797db8889dc08aec5e vp90-2-03-size-210x210-210x210-0004.i420
+e3ae1246a63ea22afd026bfb859fe165 vp90-2-03-size-210x210-210x210-0005.i420
+7e1fa363cf3f44c7a3019f29c14a6da4 vp90-2-03-size-210x210-210x210-0006.i420
+c6f26619ab5687a2a698c8766b79f2eb vp90-2-03-size-210x210-210x210-0007.i420
+be5b8c50a772afe95d72bf3cc7c4fd2f vp90-2-03-size-210x210-210x210-0008.i420
+9eab1417ac249ce31c79750143d52084 vp90-2-03-size-210x210-210x210-0009.i420
+9d2455048dbc3cdc2343a818c5a2bcb1 vp90-2-03-size-210x210-210x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x224.vp9
new file mode 100644
index 0000000..4a01426
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x224_vp9_md5
new file mode 100644
index 0000000..7bd7a82
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x224_vp9_md5
@@ -0,0 +1,10 @@
+bb903b926c4b34ae336e21d65ad8fd25 vp90-2-03-size-210x224-210x224-0001.i420
+c4c0bc3b112487e994d22176817ace3c vp90-2-03-size-210x224-210x224-0002.i420
+24e699f7a92ab1b0fe12e0b747470b5b vp90-2-03-size-210x224-210x224-0003.i420
+200f403694d3acfda63f52e8373f1420 vp90-2-03-size-210x224-210x224-0004.i420
+6df417a8ec1810562301c89724b739d1 vp90-2-03-size-210x224-210x224-0005.i420
+55757b633d8fe669fc0f507dab4fa9f7 vp90-2-03-size-210x224-210x224-0006.i420
+45bc82bee02cb45422be3ac1019896d0 vp90-2-03-size-210x224-210x224-0007.i420
+4aaf5d07d2796910767d5084556c9cf9 vp90-2-03-size-210x224-210x224-0008.i420
+f100fa26da47250b98d95a18915f521d vp90-2-03-size-210x224-210x224-0009.i420
+f5a8def53b4638b6ce7c8588d595d0ad vp90-2-03-size-210x224-210x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_210x226.vp9
new file mode 100644
index 0000000..f88afa6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_210x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_210x226_vp9_md5
new file mode 100644
index 0000000..48fa3d4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_210x226_vp9_md5
@@ -0,0 +1,10 @@
+03707b2f5c392933f7336f380423a0a1 vp90-2-03-size-210x226-210x226-0001.i420
+b388553c79573555a3b660f5e36d4e36 vp90-2-03-size-210x226-210x226-0002.i420
+a1a7fd8ba7fb0fe7733cdf5440c7c1f3 vp90-2-03-size-210x226-210x226-0003.i420
+9daff7ef71dd54951f0b75a902065259 vp90-2-03-size-210x226-210x226-0004.i420
+60218a4b8bc0a5b0b40fa560a40fb4c0 vp90-2-03-size-210x226-210x226-0005.i420
+21229bfed833468fafc27ce93db1450c vp90-2-03-size-210x226-210x226-0006.i420
+7aa290c6e503315d7aa3517258d5f63a vp90-2-03-size-210x226-210x226-0007.i420
+63fd08ae2e859ff3d874ab2c2ce41a42 vp90-2-03-size-210x226-210x226-0008.i420
+725b371247fae28ef4b912368738df64 vp90-2-03-size-210x226-210x226-0009.i420
+7cf2d8d9e464307311b499ff0c3ea05e vp90-2-03-size-210x226-210x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x196.vp9
new file mode 100644
index 0000000..8fd0876
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x196_vp9_md5
new file mode 100644
index 0000000..3edb492
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x196_vp9_md5
@@ -0,0 +1,10 @@
+3ffc096f1b42b4d319d4a9efbefc7625 vp90-2-03-size-224x196-224x196-0001.i420
+78b3655d5cad30fa6b2c2d8fd29463de vp90-2-03-size-224x196-224x196-0002.i420
+ab197553d9599b2a03aff62d1d694848 vp90-2-03-size-224x196-224x196-0003.i420
+be368d1f3d3fcc710565b5433940f0df vp90-2-03-size-224x196-224x196-0004.i420
+374c5db60ea9c110b871bb45be0efff1 vp90-2-03-size-224x196-224x196-0005.i420
+ec50085400d626de5833bc0a94d9941f vp90-2-03-size-224x196-224x196-0006.i420
+d4ae69937e2a8d9bf2023d4215749635 vp90-2-03-size-224x196-224x196-0007.i420
+9b0b81eb6d62b8014e0639932fe35bc0 vp90-2-03-size-224x196-224x196-0008.i420
+cd02d0cc268e6b6df0b2dbd3f3b137e6 vp90-2-03-size-224x196-224x196-0009.i420
+5322ba1085c114f93534e1761a0d8aa1 vp90-2-03-size-224x196-224x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x198.vp9
new file mode 100644
index 0000000..c0b6e4c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x198_vp9_md5
new file mode 100644
index 0000000..d0b35cd
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x198_vp9_md5
@@ -0,0 +1,10 @@
+cf35dffc80946e87bb9d3e18aab9d320 vp90-2-03-size-224x198-224x198-0001.i420
+a76ac92f05e9b097f8ac5882e1ffe656 vp90-2-03-size-224x198-224x198-0002.i420
+faa1e8a11c9df3e9c9a9dafbebea6d04 vp90-2-03-size-224x198-224x198-0003.i420
+905a28289c8ac793b335096ca7f84e1d vp90-2-03-size-224x198-224x198-0004.i420
+cb480fa6977baf98a74bddf213ecba82 vp90-2-03-size-224x198-224x198-0005.i420
+35224d3708e3ba1dafcc58b803d5ea77 vp90-2-03-size-224x198-224x198-0006.i420
+d166d764e87854bca47ab7a2bc8b1f9b vp90-2-03-size-224x198-224x198-0007.i420
+562f1e06ae36abba5f1fb53e3d6cd7e8 vp90-2-03-size-224x198-224x198-0008.i420
+1599cebef060f6464aeef15aacbde446 vp90-2-03-size-224x198-224x198-0009.i420
+3316ebca2864a9dc04db86069efb1dd1 vp90-2-03-size-224x198-224x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x200.vp9
new file mode 100644
index 0000000..94cc4c7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x200_vp9_md5
new file mode 100644
index 0000000..bb368ce
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x200_vp9_md5
@@ -0,0 +1,10 @@
+0819e6d715c9b4d94f05f63a7ca86199 vp90-2-03-size-224x200-224x200-0001.i420
+9b9a4b01ed4c8a93687e45245b3092a3 vp90-2-03-size-224x200-224x200-0002.i420
+3a076f5b8dba60552e84a391ee04d1c7 vp90-2-03-size-224x200-224x200-0003.i420
+7aafc561f5b96e9d286bd8deb5687774 vp90-2-03-size-224x200-224x200-0004.i420
+daa43a89ab6b2761eedaa183e33a3465 vp90-2-03-size-224x200-224x200-0005.i420
+c14874409872357b11b65f35a283e058 vp90-2-03-size-224x200-224x200-0006.i420
+37d2ef52a9c694b2596d58ed9ca0d90b vp90-2-03-size-224x200-224x200-0007.i420
+c97bc860c006896d80f52ccc0759f472 vp90-2-03-size-224x200-224x200-0008.i420
+5f8618114a723a017e39a1af695996f3 vp90-2-03-size-224x200-224x200-0009.i420
+ee8234fc5ccd41d05eb87e1510f9795e vp90-2-03-size-224x200-224x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x202.vp9
new file mode 100644
index 0000000..ac4f494
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x202_vp9_md5
new file mode 100644
index 0000000..0c6b78c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x202_vp9_md5
@@ -0,0 +1,10 @@
+e1e3b4af5910383ff6f66b6ab1a29544 vp90-2-03-size-224x202-224x202-0001.i420
+8668ef92b72f35728ebb456665d48b95 vp90-2-03-size-224x202-224x202-0002.i420
+dffc7c28f86f07bf28451292990e9594 vp90-2-03-size-224x202-224x202-0003.i420
+aebfb446fa6d48db36dbd9b5cd147f1e vp90-2-03-size-224x202-224x202-0004.i420
+e3c6cb8c5bb3a26928493bfc297ab827 vp90-2-03-size-224x202-224x202-0005.i420
+68dabae76c1d27ab0e1079d99cb6d413 vp90-2-03-size-224x202-224x202-0006.i420
+d1f7745eef748688f3871d00a7e67ef8 vp90-2-03-size-224x202-224x202-0007.i420
+36738851cc2af83fd250dea4cd63941b vp90-2-03-size-224x202-224x202-0008.i420
+16c0315c43427e7e6719806a89551703 vp90-2-03-size-224x202-224x202-0009.i420
+c4d589c0ea4cdfc1dd6dff72084c61fd vp90-2-03-size-224x202-224x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x208.vp9
new file mode 100644
index 0000000..47eae82
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x208_vp9_md5
new file mode 100644
index 0000000..1bcdd2c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x208_vp9_md5
@@ -0,0 +1,10 @@
+85f08afadfd1204d4131b9ee9c8cc10b vp90-2-03-size-224x208-224x208-0001.i420
+f893de5432a082b3dffcf7499827f548 vp90-2-03-size-224x208-224x208-0002.i420
+cb81e0d7b657bc5a4a9cf8ad75a76a77 vp90-2-03-size-224x208-224x208-0003.i420
+8a40842123965731c15fc23fb6366d1d vp90-2-03-size-224x208-224x208-0004.i420
+09c6d92af14a3fcfb12705cd5da57f2a vp90-2-03-size-224x208-224x208-0005.i420
+6bede4dc8770df534b599021b0425309 vp90-2-03-size-224x208-224x208-0006.i420
+334b0b0448e9e4e6a0cddcd2e3a0af3f vp90-2-03-size-224x208-224x208-0007.i420
+09f491f0f3870ef96cff0384cd7183d1 vp90-2-03-size-224x208-224x208-0008.i420
+c9e5f81186ac947a77b051c8f0e76eac vp90-2-03-size-224x208-224x208-0009.i420
+917565c3327bff78b53a78ea739472ff vp90-2-03-size-224x208-224x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x210.vp9
new file mode 100644
index 0000000..50d6389
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x210_vp9_md5
new file mode 100644
index 0000000..d522202
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x210_vp9_md5
@@ -0,0 +1,10 @@
+427421e5fd2087c6ff7b87a27982332f vp90-2-03-size-224x210-224x210-0001.i420
+b68311fd44e189e4174ac357d5415068 vp90-2-03-size-224x210-224x210-0002.i420
+2c822ff45be7a1ea412d21ff82c7bc1d vp90-2-03-size-224x210-224x210-0003.i420
+34659186d93516eae1dd4d9a391d1c3f vp90-2-03-size-224x210-224x210-0004.i420
+1990dd822abc3a10f511589db5aa50f4 vp90-2-03-size-224x210-224x210-0005.i420
+4a4dc076172c79d9fde3e17b47109835 vp90-2-03-size-224x210-224x210-0006.i420
+51874c79850120537fa5c405721d0107 vp90-2-03-size-224x210-224x210-0007.i420
+15d7897a128de9be90be17f1679012c9 vp90-2-03-size-224x210-224x210-0008.i420
+a8d9480accf8585e94161a5f7c371cef vp90-2-03-size-224x210-224x210-0009.i420
+8a9d3f09561b895b423ae9428f620b9b vp90-2-03-size-224x210-224x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x224.vp9
new file mode 100644
index 0000000..6397922
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x224_vp9_md5
new file mode 100644
index 0000000..1a8a55e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x224_vp9_md5
@@ -0,0 +1,10 @@
+bedd5d2725ffff06a50e23841bc2dfb8 vp90-2-03-size-224x224-224x224-0001.i420
+8c363f68b0b30f507563516aa99e23ac vp90-2-03-size-224x224-224x224-0002.i420
+9cb7d51ca4439614dc3f5980507a4d32 vp90-2-03-size-224x224-224x224-0003.i420
+b393a18de28ab6b8d1c6afd67a7794e0 vp90-2-03-size-224x224-224x224-0004.i420
+81f69ee1e3d89cb78cac192c352f7741 vp90-2-03-size-224x224-224x224-0005.i420
+aabb51f029a9a02e71524cf3500931e9 vp90-2-03-size-224x224-224x224-0006.i420
+6581aec620c508d2b42ccceaa2c6044d vp90-2-03-size-224x224-224x224-0007.i420
+993cde759158c30dcf0f0a9fdcdfb0d8 vp90-2-03-size-224x224-224x224-0008.i420
+85985ae8d35514d601800a06c8226625 vp90-2-03-size-224x224-224x224-0009.i420
+0eba1d7c193e473586e4a5c87d0e0d21 vp90-2-03-size-224x224-224x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_224x226.vp9
new file mode 100644
index 0000000..7672e82
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_224x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_224x226_vp9_md5
new file mode 100644
index 0000000..b3a8eee
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_224x226_vp9_md5
@@ -0,0 +1,10 @@
+dca556e648a576b3973fbe4b34d0328c vp90-2-03-size-224x226-224x226-0001.i420
+34a49e4aba4aca5c76ab0f751341c32b vp90-2-03-size-224x226-224x226-0002.i420
+4b7cc6d500b273efe7e30fc3a3946f74 vp90-2-03-size-224x226-224x226-0003.i420
+1960f0f1edf9196c96b0de742a3cd53c vp90-2-03-size-224x226-224x226-0004.i420
+3cb7d90178636911c5d53a5f8e75599c vp90-2-03-size-224x226-224x226-0005.i420
+84b56c60c2282f85102048cc2cf40b88 vp90-2-03-size-224x226-224x226-0006.i420
+3ca34d2978307ec0fca05130d81bcc26 vp90-2-03-size-224x226-224x226-0007.i420
+c15560be737e02ea9d1deeca0af9bb77 vp90-2-03-size-224x226-224x226-0008.i420
+391439789a6aa7bb02d7e699795a9559 vp90-2-03-size-224x226-224x226-0009.i420
+9f681e91cbcbe9920f21236b8ff093c7 vp90-2-03-size-224x226-224x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x196.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x196.vp9
new file mode 100644
index 0000000..e88ffc4
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x196.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x196_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x196_vp9_md5
new file mode 100644
index 0000000..a995846
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x196_vp9_md5
@@ -0,0 +1,10 @@
+4757a31842453f806de2f2256329547e vp90-2-03-size-226x196-226x196-0001.i420
+fe5fb955a4143091c5bfae7c4a4afe0f vp90-2-03-size-226x196-226x196-0002.i420
+93766c5a03d71f99afb7705add7b63f0 vp90-2-03-size-226x196-226x196-0003.i420
+30c91162aa6fb0ed3e47325146bb6d8a vp90-2-03-size-226x196-226x196-0004.i420
+501fe67785b970b1b62c2ae0b36b19ad vp90-2-03-size-226x196-226x196-0005.i420
+836be5e778e3d20e75c4fcd71f765b3d vp90-2-03-size-226x196-226x196-0006.i420
+21a9fd5e78212fe71719e173844bc6e6 vp90-2-03-size-226x196-226x196-0007.i420
+81b3919208e345d93dde62740b47dd93 vp90-2-03-size-226x196-226x196-0008.i420
+df010555a929ba88a2f25c6267e3786e vp90-2-03-size-226x196-226x196-0009.i420
+d2cff8282e5e7a5bbd879c73df0670c3 vp90-2-03-size-226x196-226x196-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x198.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x198.vp9
new file mode 100644
index 0000000..fa201ed
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x198.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x198_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x198_vp9_md5
new file mode 100644
index 0000000..3c4d3f5b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x198_vp9_md5
@@ -0,0 +1,10 @@
+b97087eb8c53cf56dc44576912654fb2 vp90-2-03-size-226x198-226x198-0001.i420
+219bb68a59dc166806a5b5689a943b66 vp90-2-03-size-226x198-226x198-0002.i420
+67b2ec19dd3b74d828b51912c25249d6 vp90-2-03-size-226x198-226x198-0003.i420
+73dd9625538e10a0f94d31ac9fe3db23 vp90-2-03-size-226x198-226x198-0004.i420
+51e68f201130da18beb0cb27adcf6fa9 vp90-2-03-size-226x198-226x198-0005.i420
+455d9753b3c0ac5ad7d9da022f69acd0 vp90-2-03-size-226x198-226x198-0006.i420
+60a8905a63db4cdd2560583fb6415030 vp90-2-03-size-226x198-226x198-0007.i420
+48c156f4b2c9f936487b43713a4573fd vp90-2-03-size-226x198-226x198-0008.i420
+a5c8f4190cb34b3ecd42ca8e09bf1646 vp90-2-03-size-226x198-226x198-0009.i420
+233a5d5187137e047993532fc2e725d3 vp90-2-03-size-226x198-226x198-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x200.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x200.vp9
new file mode 100644
index 0000000..a61270b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x200.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x200_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x200_vp9_md5
new file mode 100644
index 0000000..edab982
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x200_vp9_md5
@@ -0,0 +1,10 @@
+0ae27db338f73f37eaed806b1c789593 vp90-2-03-size-226x200-226x200-0001.i420
+3f69273752f43699a3bc7b22a88cc3aa vp90-2-03-size-226x200-226x200-0002.i420
+ce0dfafb59910241d2b1a2275a2c2143 vp90-2-03-size-226x200-226x200-0003.i420
+8d20f404e25766c819ee728858bcbc76 vp90-2-03-size-226x200-226x200-0004.i420
+67bc5604c5b0f6c3484b605c1f93c83a vp90-2-03-size-226x200-226x200-0005.i420
+1c82def3a06430d205cce0db7b5714de vp90-2-03-size-226x200-226x200-0006.i420
+654d7a676e3b8b64541ed8cdefbd7286 vp90-2-03-size-226x200-226x200-0007.i420
+6c80c78c7b652c5b3b117a0960e89951 vp90-2-03-size-226x200-226x200-0008.i420
+ae73e3c69ec6747c5234d58c5e1e36eb vp90-2-03-size-226x200-226x200-0009.i420
+e40d716efd8caf2d4004d299fb914328 vp90-2-03-size-226x200-226x200-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x202.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x202.vp9
new file mode 100644
index 0000000..28732e2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x202.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x202_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x202_vp9_md5
new file mode 100644
index 0000000..80e7ac2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x202_vp9_md5
@@ -0,0 +1,10 @@
+0cd2876640e71de3a6df7839bd6f0b51 vp90-2-03-size-226x202-226x202-0001.i420
+f887db6839c0cddd1ea9ae6bfd2cc16d vp90-2-03-size-226x202-226x202-0002.i420
+ff2a890cf4c4973bf181ba8424c2eadc vp90-2-03-size-226x202-226x202-0003.i420
+f69f2e4f3036a21deb43a0bf4b95771f vp90-2-03-size-226x202-226x202-0004.i420
+93f511739c19f1a3b356dda39d945c93 vp90-2-03-size-226x202-226x202-0005.i420
+7f79633c93765b504fef0324bd10fdba vp90-2-03-size-226x202-226x202-0006.i420
+d6c53d3937c9a40b227b4486452e0b33 vp90-2-03-size-226x202-226x202-0007.i420
+4e26625e8997ad6fe08ae68fbdfdbfd7 vp90-2-03-size-226x202-226x202-0008.i420
+3bf4c8ac0279351bf904cf57b0fc13c1 vp90-2-03-size-226x202-226x202-0009.i420
+12d64d856025185fa9e610dfa62b05af vp90-2-03-size-226x202-226x202-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x208.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x208.vp9
new file mode 100644
index 0000000..f88a8b8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x208.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x208_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x208_vp9_md5
new file mode 100644
index 0000000..364227a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x208_vp9_md5
@@ -0,0 +1,10 @@
+6006cac6628cf9e7cea58aec07471b06 vp90-2-03-size-226x208-226x208-0001.i420
+f7e994921248b6933920c984880ec96c vp90-2-03-size-226x208-226x208-0002.i420
+c0aeeb9d2009538d8d5e837f45e1542d vp90-2-03-size-226x208-226x208-0003.i420
+7dacf9d00e85bd52045eb47bae5225b3 vp90-2-03-size-226x208-226x208-0004.i420
+024fd008a099ae954e38a3f0a8ebb6c9 vp90-2-03-size-226x208-226x208-0005.i420
+fb6c368a1b3578ab59aa30e0b5cc4853 vp90-2-03-size-226x208-226x208-0006.i420
+07815251f7020b627c365a7a7be694c7 vp90-2-03-size-226x208-226x208-0007.i420
+db8b8f48f3693867d2bd8208cf4f929a vp90-2-03-size-226x208-226x208-0008.i420
+88b42d943c0978d832333a8a3f7b6bbc vp90-2-03-size-226x208-226x208-0009.i420
+7aa760190f9328ba4f6fa87d1d9e8d3e vp90-2-03-size-226x208-226x208-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x210.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x210.vp9
new file mode 100644
index 0000000..2a60796
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x210.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x210_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x210_vp9_md5
new file mode 100644
index 0000000..f4afd83
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x210_vp9_md5
@@ -0,0 +1,10 @@
+a6c1b7686202f5cc64335f92be595309 vp90-2-03-size-226x210-226x210-0001.i420
+3e573d4c693a39c5d6cd46b8873e99bb vp90-2-03-size-226x210-226x210-0002.i420
+d2388f6f641c8ddec98f11493f1a1390 vp90-2-03-size-226x210-226x210-0003.i420
+16473e33532ebc8de2f02077c406346b vp90-2-03-size-226x210-226x210-0004.i420
+6c75d1c01276838fce40837e373f49db vp90-2-03-size-226x210-226x210-0005.i420
+b718e7445e2b08dde78fa7f30be01346 vp90-2-03-size-226x210-226x210-0006.i420
+2f556ed5afd60b1bbae76984ce073107 vp90-2-03-size-226x210-226x210-0007.i420
+4e5d59daed044c39a14c35f18cb4fb7a vp90-2-03-size-226x210-226x210-0008.i420
+c14901a9906ffcd0eb1efc068ce32941 vp90-2-03-size-226x210-226x210-0009.i420
+3d73b7f87bcd16c1ec565b5cc8d0fe93 vp90-2-03-size-226x210-226x210-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x224.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x224.vp9
new file mode 100644
index 0000000..8735e4d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x224.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x224_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x224_vp9_md5
new file mode 100644
index 0000000..24df8e0
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x224_vp9_md5
@@ -0,0 +1,10 @@
+80fb3a643384386beadc0991f171669d vp90-2-03-size-226x224-226x224-0001.i420
+65a4a51163f49a75f8eeecd94cb2ba47 vp90-2-03-size-226x224-226x224-0002.i420
+d5b2aac9889d2991b83fd4360ada0258 vp90-2-03-size-226x224-226x224-0003.i420
+7958ff5535358567ea7df351d78256a7 vp90-2-03-size-226x224-226x224-0004.i420
+7e7413b9a61967d0ade07b81944e9a15 vp90-2-03-size-226x224-226x224-0005.i420
+40a008016adbf9673adbbc4c0edb4454 vp90-2-03-size-226x224-226x224-0006.i420
+fef7b5e2809ef79917ab394a067ef4be vp90-2-03-size-226x224-226x224-0007.i420
+91ee2360faf46a25b95927c55eea603f vp90-2-03-size-226x224-226x224-0008.i420
+a47f14a80a529f79f97accbe23188046 vp90-2-03-size-226x224-226x224-0009.i420
+3613bcd41ff13006fbba3bd0087c44f4 vp90-2-03-size-226x224-226x224-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x226.vp9 b/tests/tests/media/res/raw/vp90_2_03_size_226x226.vp9
new file mode 100644
index 0000000..c7f8202
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x226.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_03_size_226x226_vp9_md5 b/tests/tests/media/res/raw/vp90_2_03_size_226x226_vp9_md5
new file mode 100644
index 0000000..24f20a6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_03_size_226x226_vp9_md5
@@ -0,0 +1,10 @@
+f2370fc802dafdf5082beffc1907a9c6 vp90-2-03-size-226x226-226x226-0001.i420
+aad6de7b986234a1d621935b272501c9 vp90-2-03-size-226x226-226x226-0002.i420
+8a6d3784e22e3b4f735e78916fbc3821 vp90-2-03-size-226x226-226x226-0003.i420
+0c4afce19c43fdf3bb1b972810cc9126 vp90-2-03-size-226x226-226x226-0004.i420
+814a68dd76a3135221131988910f51ba vp90-2-03-size-226x226-226x226-0005.i420
+b2379c4b28dca10e67ac58631f9731c0 vp90-2-03-size-226x226-226x226-0006.i420
+b16fd651884340a428cea3fe0ac18ba6 vp90-2-03-size-226x226-226x226-0007.i420
+cb65cd4c421cfd6a19fb123ec27abbe6 vp90-2-03-size-226x226-226x226-0008.i420
+7f1d2686b9808de8ecc723b18136d57d vp90-2-03-size-226x226-226x226-0009.i420
+da7fd4bff4b6db0221c42492876c5c4d vp90-2-03-size-226x226-226x226-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_06_bilinear.vp9 b/tests/tests/media/res/raw/vp90_2_06_bilinear.vp9
new file mode 100644
index 0000000..a492d03
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_06_bilinear.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_06_bilinear_vp9_md5 b/tests/tests/media/res/raw/vp90_2_06_bilinear_vp9_md5
new file mode 100644
index 0000000..25231b98
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_06_bilinear_vp9_md5
@@ -0,0 +1,10 @@
+818a5af531c921ae58dfedc75234f3c5 -352x288-0001.i420
+f863f8c68b5c87c721d345c5a894336d -352x288-0002.i420
+3f1213e44db416530bc0717f0a795b5d -352x288-0003.i420
+4b99c16a62c3d6687c78236fa13e1f41 -352x288-0004.i420
+80f23a3f04215dd7542128e7c53d68d0 -352x288-0005.i420
+b40b7aa34a77fe773d82d75b5bdd9c13 -352x288-0006.i420
+dd4af6263d20bbaf9afedb6695c1ba67 -352x288-0007.i420
+1f2ccf88f15c10e3c27b2368dacc3727 -352x288-0008.i420
+232b027c4e9b598f50d078bb7b7a165e -352x288-0009.i420
+2b44367332aa0fe42362d61f18e7f8dd -352x288-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_07_frame_parallel.vp9 b/tests/tests/media/res/raw/vp90_2_07_frame_parallel.vp9
new file mode 100644
index 0000000..2c80a2d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_07_frame_parallel.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_07_frame_parallel_1.vp9 b/tests/tests/media/res/raw/vp90_2_07_frame_parallel_1.vp9
new file mode 100644
index 0000000..10f6eb7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_07_frame_parallel_1.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_07_frame_parallel_1_vp9_md5 b/tests/tests/media/res/raw/vp90_2_07_frame_parallel_1_vp9_md5
new file mode 100644
index 0000000..a6261c8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_07_frame_parallel_1_vp9_md5
@@ -0,0 +1,40 @@
+b5d461894f957709576d15f6dce3d69e vp90-2-07-frame_parallel-1.webm-352x288-0001.i420
+54e45dfe575d9843c198270f62154c09 vp90-2-07-frame_parallel-1.webm-352x288-0002.i420
+c3798fe06d2c0adbb43410b76c67c0cd vp90-2-07-frame_parallel-1.webm-352x288-0003.i420
+2cc4ad256a586ff2be650adce4d7f332 vp90-2-07-frame_parallel-1.webm-352x288-0004.i420
+3e63839f0aaedfeaf71cf2868e506bdd vp90-2-07-frame_parallel-1.webm-352x288-0005.i420
+ca0a10c9144084231f801fa6f0433eb4 vp90-2-07-frame_parallel-1.webm-352x288-0006.i420
+c920d177c21a8b0dee8fdbce1edfd75c vp90-2-07-frame_parallel-1.webm-352x288-0007.i420
+6afe32287ff1dcaa42630bbf9fe32bad vp90-2-07-frame_parallel-1.webm-352x288-0008.i420
+0bc39f7c6fbc1fb18dce622d17b0856e vp90-2-07-frame_parallel-1.webm-352x288-0009.i420
+6f92688afcd228649627c1757417bfe5 vp90-2-07-frame_parallel-1.webm-352x288-0010.i420
+338920379e1746eff6bc1c53553c400e vp90-2-07-frame_parallel-1.webm-352x288-0011.i420
+2beb514ca62779c7c20e1dff0ccc496a vp90-2-07-frame_parallel-1.webm-352x288-0012.i420
+e7b4dcc8437af45f363a3b24439323d2 vp90-2-07-frame_parallel-1.webm-352x288-0013.i420
+10bac4f44ae04e2d9f3219044a273f3c vp90-2-07-frame_parallel-1.webm-352x288-0014.i420
+45581dbebb5074f698ad6d22d52f02b6 vp90-2-07-frame_parallel-1.webm-352x288-0015.i420
+9480f12b47b834003d6d572b9fdfdda1 vp90-2-07-frame_parallel-1.webm-352x288-0016.i420
+b31f361b8971a56338b3960c18177b7c vp90-2-07-frame_parallel-1.webm-352x288-0017.i420
+79d631a53008d36f8ff5248a8592ffdc vp90-2-07-frame_parallel-1.webm-352x288-0018.i420
+0efc005919f5a1cdded77ae91245d3be vp90-2-07-frame_parallel-1.webm-352x288-0019.i420
+bf0d1144000094b3eb333b3dab466ace vp90-2-07-frame_parallel-1.webm-352x288-0020.i420
+80c0d7ccfa044dc8fe1967951c4d4fea vp90-2-07-frame_parallel-1.webm-352x288-0021.i420
+28c8e8c406a804cde7feba37e0fda689 vp90-2-07-frame_parallel-1.webm-352x288-0022.i420
+8bef0cfaa4c298d93d20b88c17ef4864 vp90-2-07-frame_parallel-1.webm-352x288-0023.i420
+9488e35310228d5930fccc4a2ee5a96d vp90-2-07-frame_parallel-1.webm-352x288-0024.i420
+638394b668015141ba1ff97c89034e32 vp90-2-07-frame_parallel-1.webm-352x288-0025.i420
+85aff2c821b25962d3f72208a5f05992 vp90-2-07-frame_parallel-1.webm-352x288-0026.i420
+ec68bb46a7ef2e90c07b7dcfb406eb20 vp90-2-07-frame_parallel-1.webm-352x288-0027.i420
+7b0f3a57f320b1fe33ad5ac03ba0e568 vp90-2-07-frame_parallel-1.webm-352x288-0028.i420
+da461e5510f591c17675d9d7ec9532c4 vp90-2-07-frame_parallel-1.webm-352x288-0029.i420
+d2997aa173f757dd2ef78b58f5d5a109 vp90-2-07-frame_parallel-1.webm-352x288-0030.i420
+ff70094752edf348767a47db71d2dfd0 vp90-2-07-frame_parallel-1.webm-352x288-0031.i420
+52ec9a87ad6df24714fbe6b3384b3f10 vp90-2-07-frame_parallel-1.webm-352x288-0032.i420
+665a0ee3f3ce1a100aae8ff12e8f5193 vp90-2-07-frame_parallel-1.webm-352x288-0033.i420
+98e6fcabfa61b3ca20844c4ce02cdc59 vp90-2-07-frame_parallel-1.webm-352x288-0034.i420
+8e9a1c517df8a280b27e525e3b60ec6f vp90-2-07-frame_parallel-1.webm-352x288-0035.i420
+58701ab08edeed3f9f969742b64dbb35 vp90-2-07-frame_parallel-1.webm-352x288-0036.i420
+d901de4fdc5fc2352578116bacefade2 vp90-2-07-frame_parallel-1.webm-352x288-0037.i420
+3b9d9902ea331b3fb5ceb255e66731b3 vp90-2-07-frame_parallel-1.webm-352x288-0038.i420
+3ac2e9b87a373667686c82fc7f14e6be vp90-2-07-frame_parallel-1.webm-352x288-0039.i420
+fe198064dd4e6ef3ef829ba41c92d002 vp90-2-07-frame_parallel-1.webm-352x288-0040.i420
diff --git a/tests/tests/media/res/raw/vp90_2_07_frame_parallel_vp9_md5 b/tests/tests/media/res/raw/vp90_2_07_frame_parallel_vp9_md5
new file mode 100644
index 0000000..7e598ae
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_07_frame_parallel_vp9_md5
@@ -0,0 +1,10 @@
+4480e19849cb7b042355a42011fa2d89 vp90-2-07-frame_parallel-352x240-0001.i420
+1d48490e61c0109b301938facb648987 vp90-2-07-frame_parallel-352x240-0002.i420
+9c9140e23a56114ea3cc9bae01c6f2be vp90-2-07-frame_parallel-352x240-0003.i420
+cbdd934532bd9c9c27079d17e570e4af vp90-2-07-frame_parallel-352x240-0004.i420
+db86f11f02c0936371f59a292e32976d vp90-2-07-frame_parallel-352x240-0005.i420
+6fc5f675eb7e1ccdfa5230208dcbc608 vp90-2-07-frame_parallel-352x240-0006.i420
+39fcd15c8cf524a9acce7a66982acec5 vp90-2-07-frame_parallel-352x240-0007.i420
+8c24475c41ec9d5aaa7954f997da12c4 vp90-2-07-frame_parallel-352x240-0008.i420
+5b9747332e303f62b73d4cd2728ac93c vp90-2-07-frame_parallel-352x240-0009.i420
+706f3fc0042b9e6e8b91318ecd55fce8 vp90-2-07-frame_parallel-352x240-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x2.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_1x2.vp9
new file mode 100644
index 0000000..de3593a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x2.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x2_frame_parallel.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_1x2_frame_parallel.vp9
new file mode 100644
index 0000000..1895056
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x2_frame_parallel.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x2_frame_parallel_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_1x2_frame_parallel_vp9_md5
new file mode 100644
index 0000000..7e6b4f2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x2_frame_parallel_vp9_md5
@@ -0,0 +1,10 @@
+124dcaf4393bbc676cefc1dcfc1474b9 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0001.i420
+02e0c145da3e3c711f13dad6d5d9f2ec /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0002.i420
+bd276b44124d01ea89cb428a3532a87e /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0003.i420
+fc1eb96ba3b93382a8cf3dee39928d85 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0004.i420
+0b7b92b084684377795f6fcc549f7677 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0005.i420
+208972b2d34f0a7a6616570d8279c1f1 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0006.i420
+33f15b325f9367cf1f58e2e25ccc7bed /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0007.i420
+d7f75036195e89dcbcaba566c1d6cad8 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0008.i420
+bdc3a5b228f0afa3f969d5f99685a501 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0009.i420
+d436084146d6be84df15f5fb94067d53 /tmp/test-vector/vp90-2-08-tile_1x2_frame_parallel-1920x1080-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x2_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_1x2_vp9_md5
new file mode 100644
index 0000000..f979f7f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x2_vp9_md5
@@ -0,0 +1,10 @@
+124dcaf4393bbc676cefc1dcfc1474b9 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0001.i420
+5f3357dc102c9db11e7b68d277f31f99 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0002.i420
+a5fb34b4a52fbc7b8290bffe988ffb01 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0003.i420
+1405fa1086ac63d4f5e8ed1ca0ad192a /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0004.i420
+0ead62c1d7c7c44f316e601d8fea16ba /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0005.i420
+204e05b399becce6e936bb3ac739fbe3 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0006.i420
+a27c70e46f6b2c40d6d0a13befede3ac /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0007.i420
+71434072992ec693ae809086760cad22 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0008.i420
+790a525234048c0645cc81f6a042c9c3 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0009.i420
+751b37a7b9401a5ca30dc2673070f881 /tmp/test-vector/vp90-2-08-tile_1x2-1920x1080-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x4.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_1x4.vp9
new file mode 100644
index 0000000..2cc32ae
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x4.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x4_frame_parallel.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_1x4_frame_parallel.vp9
new file mode 100644
index 0000000..d712a9c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x4_frame_parallel.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x4_frame_parallel_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_1x4_frame_parallel_vp9_md5
new file mode 100644
index 0000000..0541f98
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x4_frame_parallel_vp9_md5
@@ -0,0 +1,10 @@
+c8a7f0299fb945318bbb6fd531885339 /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0001.i420
+88001dece48c52b0f34afc9137915c9e /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0002.i420
+71c3bc238c76f1e3a81bc70aa7dcacfc /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0003.i420
+32726efd04e67dc09c055481f0189c76 /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0004.i420
+7c8fa7372885d16b73f79cbddfd7d45c /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0005.i420
+0d9a3324f574bccd9903ee040eee1787 /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0006.i420
+630fb9507a52803b50ea959a36ff60b8 /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0007.i420
+d5d7b249db773ec3c5b49567aff761e9 /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0008.i420
+b480f582b52d291aeffb97e6d572731b /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0009.i420
+be72a4c2f29317441344cc4d73b24333 /tmp/test-vector/vp90-2-08-tile_1x4_frame_parallel-1920x1080-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x4_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_1x4_vp9_md5
new file mode 100644
index 0000000..23297f5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x4_vp9_md5
@@ -0,0 +1,10 @@
+c8a7f0299fb945318bbb6fd531885339 /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0001.i420
+22dde3e7feb2177aa350db7331e8fa8f /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0002.i420
+ba644eea2bd5cded05a7b82224a02d30 /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0003.i420
+0611f83948b22eb4bd5973fa0485dcda /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0004.i420
+a8eea6193af51dbd06d953165b3de261 /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0005.i420
+1e76d8ec66941c9185e0747307a1496c /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0006.i420
+d8404c3e80c2773173e362ff622b6f3c /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0007.i420
+beed5600864a9b961c983d7a7a670bc1 /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0008.i420
+9efbe9228f6a437fe450215f711ea429 /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0009.i420
+1b65f47a5c11c5b763123d337482bd92 /tmp/test-vector/vp90-2-08-tile_1x4-1920x1080-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x8.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_1x8.vp9
new file mode 100644
index 0000000..4e9374f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x8.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x8_frame_parallel.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_1x8_frame_parallel.vp9
new file mode 100644
index 0000000..ba4e864
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x8_frame_parallel.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x8_frame_parallel_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_1x8_frame_parallel_vp9_md5
new file mode 100644
index 0000000..f36f297
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x8_frame_parallel_vp9_md5
@@ -0,0 +1,10 @@
+f91ceda125d592a3f9537d02df06c4f3 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0001.i420
+563dae097075cd4002b16ffb2be42cf2 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0002.i420
+1f035d79632516b58c56813c113e0f23 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0003.i420
+0db334dafa73ec37699a96e21bf065d0 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0004.i420
+445a1d62a17f7362c1a14179bededcab /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0005.i420
+4c80d03262518f957c54afd6e02d3610 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0006.i420
+bc6be97c7e509af0903509a260f5ccb6 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0007.i420
+27a679a8bbf2eef3eb1dc6cb221ec467 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0008.i420
+eb3b064727f265bd29407f334a51c1ab /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0009.i420
+3e0caeeef59797f9ec278e190170c285 /tmp/vids/vp90-2-08-tile_1x8_frame_parallel-3840x2160-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_1x8_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_1x8_vp9_md5
new file mode 100644
index 0000000..a13a4d7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_1x8_vp9_md5
@@ -0,0 +1,10 @@
+f91ceda125d592a3f9537d02df06c4f3 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0001.i420
+a911be78a743ed0f21463bfb82efbd44 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0002.i420
+85d7cddba48b9e26b089da7f40fd4c71 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0003.i420
+39241fe3e171fafbc95966c03042699d /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0004.i420
+7b8500c53fce2702d204b6fc888f33fb /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0005.i420
+8197c61dcecdbd975fe54771f34c5df2 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0006.i420
+f28ebf18412521df51b9d6a3ffd44f4b /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0007.i420
+0d576800a02952e825f1721fc13ac695 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0008.i420
+0eb34a14d7a89ee4c951759a35673b13 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0009.i420
+11fb21038d63e3b431f92e0a4152c2f4 /tmp/vids/vp90-2-08-tile_1x8-3840x2160-0010.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_4x1.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_4x1.vp9
new file mode 100644
index 0000000..e4f9580
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_4x1.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_4x1_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_4x1_vp9_md5
new file mode 100644
index 0000000..85d3f2a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_4x1_vp9_md5
@@ -0,0 +1,5 @@
+82fe82552fc693418e68f7757c67bbcb vp90-2-08-tile-4x1-1920x1080-0001.i420
+28db6328c54d2dbe7e9efae5ca58cec8 vp90-2-08-tile-4x1-1920x1080-0002.i420
+72f6459dd217ddd05f42cd9e8d6f689f vp90-2-08-tile-4x1-1920x1080-0003.i420
+12eeebc1533f812d01df0e2b2b8cf0f3 vp90-2-08-tile-4x1-1920x1080-0004.i420
+7ddc1f11bb28f6ad235832e6a1bb88dd vp90-2-08-tile-4x1-1920x1080-0005.i420
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_4x4.vp9 b/tests/tests/media/res/raw/vp90_2_08_tile_4x4.vp9
new file mode 100644
index 0000000..99e18c7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_4x4.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_08_tile_4x4_vp9_md5 b/tests/tests/media/res/raw/vp90_2_08_tile_4x4_vp9_md5
new file mode 100644
index 0000000..5bb175c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_08_tile_4x4_vp9_md5
@@ -0,0 +1,5 @@
+a3b9b715a7e2aed15430faabb3c8b7b3 vp90-2-08-tile-4x4-1920x1080-0001.i420
+85fa2105aa554e680056d1a413ac9673 vp90-2-08-tile-4x4-1920x1080-0002.i420
+4abb371be22d7914bb62b30d901c30ce vp90-2-08-tile-4x4-1920x1080-0003.i420
+83c2528204ae3fd4d4cc8fc67b641d3a vp90-2-08-tile-4x4-1920x1080-0004.i420
+86fcc862b8c8d64690ba3c4a6bff9f74 vp90-2-08-tile-4x4-1920x1080-0005.i420
diff --git a/tests/tests/media/res/raw/vp90_2_09_aq2.vp9 b/tests/tests/media/res/raw/vp90_2_09_aq2.vp9
new file mode 100644
index 0000000..26c09a5
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_09_aq2.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_09_aq2_vp9_md5 b/tests/tests/media/res/raw/vp90_2_09_aq2_vp9_md5
new file mode 100644
index 0000000..57ce2c8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_09_aq2_vp9_md5
@@ -0,0 +1,100 @@
+7fd2573f979a4c0fcc74c6ed37599738 vp90-2-09-aq2-352x240-0001.i420
+c2fba96de0561d78d96425813bdf0da0 vp90-2-09-aq2-352x240-0002.i420
+108b4bfeae261da9758675bce8b4645f vp90-2-09-aq2-352x240-0003.i420
+43b6e3bb1c3f6d15033f16fbd4355265 vp90-2-09-aq2-352x240-0004.i420
+e5a63b53ba5c19370c6f5fdb812014b5 vp90-2-09-aq2-352x240-0005.i420
+de4aa11cfd57d3fa11c8e29faec64bea vp90-2-09-aq2-352x240-0006.i420
+b70e555bc41eafa68db19d81780fe7b9 vp90-2-09-aq2-352x240-0007.i420
+8a49e3307faef41ecfecfdaa29f48d1f vp90-2-09-aq2-352x240-0008.i420
+ed01509dcb01ba6644137e7f0f588f13 vp90-2-09-aq2-352x240-0009.i420
+15630dcfe0ec0f27abace3e2ac80d47a vp90-2-09-aq2-352x240-0010.i420
+2f023d334f0d0d7ea7724ddd075b41a3 vp90-2-09-aq2-352x240-0011.i420
+3fd72535813e4943d1e4b19f7e554b00 vp90-2-09-aq2-352x240-0012.i420
+360db62794959e018a04c3650e832d60 vp90-2-09-aq2-352x240-0013.i420
+33638c46202958cabd78356f18101b88 vp90-2-09-aq2-352x240-0014.i420
+d8a3d7541654307f3b500cb6399fccd1 vp90-2-09-aq2-352x240-0015.i420
+cd2a41d7d0f21c02919ffb87b9510b55 vp90-2-09-aq2-352x240-0016.i420
+54b8f6b3d7e2edb67db7c3aa7f5a973b vp90-2-09-aq2-352x240-0017.i420
+ddabc76c8b2af158e5feed0f48106429 vp90-2-09-aq2-352x240-0018.i420
+b22c40581501676d588a77b502cb5e48 vp90-2-09-aq2-352x240-0019.i420
+e25c4976462fe37b0119e719e7a9a65b vp90-2-09-aq2-352x240-0020.i420
+1fcf289ba81a469926b63e9fa70fc184 vp90-2-09-aq2-352x240-0021.i420
+6a7392c22ffac7c6a4bfe7012e8dfa29 vp90-2-09-aq2-352x240-0022.i420
+9b74dc670c67073a582b3c8d390caaf5 vp90-2-09-aq2-352x240-0023.i420
+23b18dc9b7eb27b55e0068c1d75de8ad vp90-2-09-aq2-352x240-0024.i420
+0a94a263b90e08e88909deafd5c42b7c vp90-2-09-aq2-352x240-0025.i420
+9b940506b41816d2030f7a2089d83ea3 vp90-2-09-aq2-352x240-0026.i420
+da88cae2ec9324ad19365871ec893d45 vp90-2-09-aq2-352x240-0027.i420
+323cf97cddde5a9cea5f338b7ab17860 vp90-2-09-aq2-352x240-0028.i420
+455506b023df603e494bcc36ffcce179 vp90-2-09-aq2-352x240-0029.i420
+7dc8cf924ca17b6f19c7ed5e7d584835 vp90-2-09-aq2-352x240-0030.i420
+88e4c47e343182051fef005676fc3112 vp90-2-09-aq2-352x240-0031.i420
+e4891dfcc239d80f3240b85fe48f3957 vp90-2-09-aq2-352x240-0032.i420
+e559abcb6717ca8b211159010beebef8 vp90-2-09-aq2-352x240-0033.i420
+3b96d340f65e415d40d60bf6a3bedefc vp90-2-09-aq2-352x240-0034.i420
+51131241975195394fb3eaa13ca1b43f vp90-2-09-aq2-352x240-0035.i420
+ceefc4774251000943f2d58c68f2b3d3 vp90-2-09-aq2-352x240-0036.i420
+76524ef8a7f1ab5199124e8bff7bc559 vp90-2-09-aq2-352x240-0037.i420
+906cf4fc07aacb1f0a3ceaf7eeda2e74 vp90-2-09-aq2-352x240-0038.i420
+c7ad9d7bc30af316285b962b9eda4c9a vp90-2-09-aq2-352x240-0039.i420
+424a7133c0bb45a2601733a39f8d70fa vp90-2-09-aq2-352x240-0040.i420
+e76eac1e8e9529609ad1bf3e4c44e4d0 vp90-2-09-aq2-352x240-0041.i420
+e238dcef853fed9f7322cb1d73dceef5 vp90-2-09-aq2-352x240-0042.i420
+a0f2d7cd7f628fca6992ccb2ca418133 vp90-2-09-aq2-352x240-0043.i420
+4d07e59c0935554b624409bd904264ef vp90-2-09-aq2-352x240-0044.i420
+d0944fdf52b02c4ff8fd7fcb944ae00c vp90-2-09-aq2-352x240-0045.i420
+f719c346201b393262d4764bc989c4fd vp90-2-09-aq2-352x240-0046.i420
+951d18cb2791c55ebed8321dba537eb9 vp90-2-09-aq2-352x240-0047.i420
+f764f5aaac4f19b131377e16d034de9a vp90-2-09-aq2-352x240-0048.i420
+871f7a2201dd951ba541625219a8f000 vp90-2-09-aq2-352x240-0049.i420
+05e9bf3f38aacd65a796400247c8d149 vp90-2-09-aq2-352x240-0050.i420
+7bdc6fc1fe6a1e24cb952e10ed19ab68 vp90-2-09-aq2-352x240-0051.i420
+a92e8a9e7ba4d24adcf63ab897057e68 vp90-2-09-aq2-352x240-0052.i420
+7ec84b978b27052954fac85142582c2c vp90-2-09-aq2-352x240-0053.i420
+10153d3889093a27aa2aa7a4380d6372 vp90-2-09-aq2-352x240-0054.i420
+1313e1ab4c7c6c01b3b25ff7fc84da9f vp90-2-09-aq2-352x240-0055.i420
+810d9122895dcb90fae58be03af9980b vp90-2-09-aq2-352x240-0056.i420
+f77fb637d12d958099d534f4a1689eb7 vp90-2-09-aq2-352x240-0057.i420
+3570f0094d3f06efa648ff4d9db2a25d vp90-2-09-aq2-352x240-0058.i420
+8f22721b7e56e04d41d2af7cbf2ca349 vp90-2-09-aq2-352x240-0059.i420
+fee5d638fa94a6d1a2fa1dfc86a3f131 vp90-2-09-aq2-352x240-0060.i420
+c9e2f58d5f3f8c3ad527e9bd53e12372 vp90-2-09-aq2-352x240-0061.i420
+6507534d0c9fbd22c76f1f7753f000ce vp90-2-09-aq2-352x240-0062.i420
+cd944cf2a7dbd30ab4fc4b99f4041379 vp90-2-09-aq2-352x240-0063.i420
+15bbc0674190eeb1112a27746dce3726 vp90-2-09-aq2-352x240-0064.i420
+7270c42f643a9f27095dade9f1b6b62e vp90-2-09-aq2-352x240-0065.i420
+7f47919091ccd7072a2068904f582679 vp90-2-09-aq2-352x240-0066.i420
+1e3c77d769a978bf9dc9188c0f1ed105 vp90-2-09-aq2-352x240-0067.i420
+4a4613749f272b7a04e6ead37844f73c vp90-2-09-aq2-352x240-0068.i420
+8967e0f52af43110004dce3f78c8fc75 vp90-2-09-aq2-352x240-0069.i420
+e3b979ec8ed4e389abaeea149b86b407 vp90-2-09-aq2-352x240-0070.i420
+fd3c72c5249c214a85e0957279090781 vp90-2-09-aq2-352x240-0071.i420
+7fe861180df75e21f4b8937ae506d601 vp90-2-09-aq2-352x240-0072.i420
+8804a39483b5a8d7ae03003ee8b3152a vp90-2-09-aq2-352x240-0073.i420
+30a1b0bd147277f8fc50de11c2c8dc93 vp90-2-09-aq2-352x240-0074.i420
+7cb788efedd325f45bd4785f89432115 vp90-2-09-aq2-352x240-0075.i420
+a162c8ab7fa0dafdc3313a69bc7f1e38 vp90-2-09-aq2-352x240-0076.i420
+83905de481bd1cafa16cd96698337c25 vp90-2-09-aq2-352x240-0077.i420
+3d75f99043ea4bf2364844474e180079 vp90-2-09-aq2-352x240-0078.i420
+89975274a8a72af7d2cdee9fbe907852 vp90-2-09-aq2-352x240-0079.i420
+e05c9a7af0ea61d4ef4476de4d7c97cd vp90-2-09-aq2-352x240-0080.i420
+dfc99210a942a7427033cce9b596e0fa vp90-2-09-aq2-352x240-0081.i420
+544361eecb8c3b45feb1dbef5c0a39a2 vp90-2-09-aq2-352x240-0082.i420
+7aaae6bbf8af4f7f6556f2285a9d9476 vp90-2-09-aq2-352x240-0083.i420
+485716ddd13576464d1ca47b4859cc22 vp90-2-09-aq2-352x240-0084.i420
+00194b66bafdb6a252852bd087200c6b vp90-2-09-aq2-352x240-0085.i420
+d21b316ba1006c2381d78e5b7652b12a vp90-2-09-aq2-352x240-0086.i420
+56506d53dc2333ccddcedb449977ce57 vp90-2-09-aq2-352x240-0087.i420
+0c6787858208959270dde59e38c544ca vp90-2-09-aq2-352x240-0088.i420
+913b906f645964f57913db70e21aa6d8 vp90-2-09-aq2-352x240-0089.i420
+f9c5d447dd4c060d3610d22b6ff8f1d7 vp90-2-09-aq2-352x240-0090.i420
+ece0a0110c14dccde0ea4d0484b60d38 vp90-2-09-aq2-352x240-0091.i420
+fbcb7e878673c8287a1ed57a6feef818 vp90-2-09-aq2-352x240-0092.i420
+be5aed5dd5538c3ad8c9d88fb4a4207f vp90-2-09-aq2-352x240-0093.i420
+4c668204dd2c45d039bf7c5f44203803 vp90-2-09-aq2-352x240-0094.i420
+06f9b1207289ed7fbf03c4be3f0349f5 vp90-2-09-aq2-352x240-0095.i420
+26275672bc752789d0a175ca48344643 vp90-2-09-aq2-352x240-0096.i420
+1b56fde58558ec9ae00f24815c13f672 vp90-2-09-aq2-352x240-0097.i420
+ff65dec4cab5d10ea34321f34d369b5e vp90-2-09-aq2-352x240-0098.i420
+3d419dded34673cf487b39106af08da6 vp90-2-09-aq2-352x240-0099.i420
+ab8a99b2a88bab0238e5d3d3204098e0 vp90-2-09-aq2-352x240-0100.i420
diff --git a/tests/tests/media/res/raw/vp90_2_09_lf_deltas.vp9 b/tests/tests/media/res/raw/vp90_2_09_lf_deltas.vp9
new file mode 100644
index 0000000..72c747b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_09_lf_deltas.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_09_lf_deltas_vp9_md5 b/tests/tests/media/res/raw/vp90_2_09_lf_deltas_vp9_md5
new file mode 100644
index 0000000..b212aaa
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_09_lf_deltas_vp9_md5
@@ -0,0 +1,30 @@
+a83c7f4602f595fd09e97f8c8a7277ec vp90-2-09-lf_deltas-352x240-0001.i420
+53e1a3fd44932883a8dd112bbb0e359f vp90-2-09-lf_deltas-352x240-0002.i420
+4bb16d168f9f0a7702c31a68bb8ff36c vp90-2-09-lf_deltas-352x240-0003.i420
+1b2df157913aba96553aaf8d51491bf3 vp90-2-09-lf_deltas-352x240-0004.i420
+9d041532e42fca7a4062cd3e9b75413b vp90-2-09-lf_deltas-352x240-0005.i420
+0dbac5ca06e13714d10e99042aefe375 vp90-2-09-lf_deltas-352x240-0006.i420
+bb83a507a65d2a640b08f42a77bb37f6 vp90-2-09-lf_deltas-352x240-0007.i420
+176f992d37c7daa36135cddb49398de3 vp90-2-09-lf_deltas-352x240-0008.i420
+c41834f72b3281cf6aaa66fd7416e6c3 vp90-2-09-lf_deltas-352x240-0009.i420
+790d4e6b1609dec782ff978e2003d318 vp90-2-09-lf_deltas-352x240-0010.i420
+449622f741f7577c1d721f2e9eb25091 vp90-2-09-lf_deltas-352x240-0011.i420
+8ef8543f7895c87ab04491b0150628e5 vp90-2-09-lf_deltas-352x240-0012.i420
+88ef626aca4b2bcb8c58a69db20a7b02 vp90-2-09-lf_deltas-352x240-0013.i420
+4b2f7adc2e1872ecdd9ffa7d1f1df4a6 vp90-2-09-lf_deltas-352x240-0014.i420
+7b162660225022ef31e39c34fee3418e vp90-2-09-lf_deltas-352x240-0015.i420
+2b439a4b846edcc69cdf6075de5ac8fb vp90-2-09-lf_deltas-352x240-0016.i420
+ba2eb1ba0ed9abf701a53a94c9c626fc vp90-2-09-lf_deltas-352x240-0017.i420
+9fbec5d5334fd5e917feee756b652d93 vp90-2-09-lf_deltas-352x240-0018.i420
+93b5eb99ea54abc5fa90c5674499e27e vp90-2-09-lf_deltas-352x240-0019.i420
+04a98408e9b0aed28932ef1dfdcfdb6c vp90-2-09-lf_deltas-352x240-0020.i420
+9856ba976bed30bc790a3f28e926b092 vp90-2-09-lf_deltas-352x240-0021.i420
+2b0f450e9724cfc57b846148ff876e51 vp90-2-09-lf_deltas-352x240-0022.i420
+163757f3529369b9789ea606387b831d vp90-2-09-lf_deltas-352x240-0023.i420
+de5ed2aff936c54f3378d0dcc2575d13 vp90-2-09-lf_deltas-352x240-0024.i420
+1f642826b8a6fb111c7c6130481dab89 vp90-2-09-lf_deltas-352x240-0025.i420
+b8e3a77c7d3c5c56f67aa7409fb5404c vp90-2-09-lf_deltas-352x240-0026.i420
+eb06cb4f471e42d7fc06929a442cca8b vp90-2-09-lf_deltas-352x240-0027.i420
+53471649a5080b306d2c04a4f7673bdf vp90-2-09-lf_deltas-352x240-0028.i420
+70996be0cc5d2bd97025015dd50caa99 vp90-2-09-lf_deltas-352x240-0029.i420
+ff3280a8562fdf6697c4a7cb9c1bf0a0 vp90-2-09-lf_deltas-352x240-0030.i420
diff --git a/tests/tests/media/res/raw/vp90_2_09_subpixel_00.vp9 b/tests/tests/media/res/raw/vp90_2_09_subpixel_00.vp9
new file mode 100644
index 0000000..78900f9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_09_subpixel_00.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_09_subpixel_00_vp9_md5 b/tests/tests/media/res/raw/vp90_2_09_subpixel_00_vp9_md5
new file mode 100644
index 0000000..1144632
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_09_subpixel_00_vp9_md5
@@ -0,0 +1,20 @@
+50233551e96b74ebfdaabbc8a154303c vp90-hantro-stream-001-320x180-0001.i420
+047109ae2e488be8ee953dca4f09a0e2 vp90-hantro-stream-001-320x180-0002.i420
+5e2ba01240e39566a607f10f0d7eaed3 vp90-hantro-stream-001-320x180-0003.i420
+01f1c635ce56efcc13def2ac3bcccc3f vp90-hantro-stream-001-320x180-0004.i420
+6e800d75da797409eb2f5b458027b05d vp90-hantro-stream-001-320x180-0005.i420
+a88b9c2cfad5367d934fd067c2c6452d vp90-hantro-stream-001-320x180-0006.i420
+a898a33e443dba4c2d61c27caa0fb068 vp90-hantro-stream-001-320x180-0007.i420
+321f16df155169f1fbd117a258b065ed vp90-hantro-stream-001-320x180-0008.i420
+a71b4df17c37e423a2a6129be8058c66 vp90-hantro-stream-001-320x180-0009.i420
+b168dad8dd0be2e945ada495320e1ec3 vp90-hantro-stream-001-320x180-0010.i420
+4b4e227f6558b9a0e80bbeaebdc50b63 vp90-hantro-stream-001-320x180-0011.i420
+929ad97d05c62b56d908378beeedb68e vp90-hantro-stream-001-320x180-0012.i420
+f952dc4b2a6e6cdcb0740e67eec87c96 vp90-hantro-stream-001-320x180-0013.i420
+f42500b60e2bbfee44b7e5b4068d9061 vp90-hantro-stream-001-320x180-0014.i420
+802f7975005cc8d77a3801b72ee08ca1 vp90-hantro-stream-001-320x180-0015.i420
+e685e147c9400dd6742c749dc1e18fd6 vp90-hantro-stream-001-320x180-0016.i420
+4080f9db1e9a98478af9c0575a7f31fc vp90-hantro-stream-001-320x180-0017.i420
+70fcce378d2bade12d2dab44b3fbd4b6 vp90-hantro-stream-001-320x180-0018.i420
+81e539130d2dbb2eb69fe63eb1bb9cbb vp90-hantro-stream-001-320x180-0019.i420
+2952c0eae93f3dadd1aa84c50d3fd6d2 vp90-hantro-stream-001-320x180-0020.i420
diff --git a/tests/tests/media/res/raw/vp90_2_10_show_existing_frame.vp9 b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame.vp9
new file mode 100644
index 0000000..bd5531e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_10_show_existing_frame2.vp9 b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame2.vp9
new file mode 100644
index 0000000..665a236
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame2.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_10_show_existing_frame2_vp9_md5 b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame2_vp9_md5
new file mode 100644
index 0000000..51940b6
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame2_vp9_md5
@@ -0,0 +1,16 @@
+382b12c33cd86b38758706b8ebca8a85 -352x288-0001.i420
+799544370b35c91711a5b49a28cf86a8 -352x288-0002.i420
+7218eb4b6d1c7aea4f96ee47ad675e8e -352x288-0003.i420
+627466200370e6ad60ea570d31be66e3 -352x288-0004.i420
+7dc65a2af108379f2b9265a9a1ea7cf8 -352x288-0005.i420
+c979e2f084760775a567f60f79f28198 -352x288-0006.i420
+fe668a6417aa0543e4ed4d1c67c5cbcb -352x288-0007.i420
+bf9901e39815fa93cce0ed5b02b2ef2d -352x288-0008.i420
+627466200370e6ad60ea570d31be66e3 -352x288-0009.i420
+7dc65a2af108379f2b9265a9a1ea7cf8 -352x288-0010.i420
+c979e2f084760775a567f60f79f28198 -352x288-0011.i420
+fe668a6417aa0543e4ed4d1c67c5cbcb -352x288-0012.i420
+bf9901e39815fa93cce0ed5b02b2ef2d -352x288-0013.i420
+627466200370e6ad60ea570d31be66e3 -352x288-0014.i420
+7dc65a2af108379f2b9265a9a1ea7cf8 -352x288-0015.i420
+c979e2f084760775a567f60f79f28198 -352x288-0016.i420
diff --git a/tests/tests/media/res/raw/vp90_2_10_show_existing_frame_vp9_md5 b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame_vp9_md5
new file mode 100644
index 0000000..85d421d
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_10_show_existing_frame_vp9_md5
@@ -0,0 +1,13 @@
+18981342ec178e082519451062c3a67f vp90-2-10-show-existing-frame-352x288-0001.i420
+04ab9dbeac49ec31be58f6e671698e05 vp90-2-10-show-existing-frame-352x288-0002.i420
+4ed58a0ba93a5d97a232a50c5876cda2 vp90-2-10-show-existing-frame-352x288-0003.i420
+a41f00034923e56ba51a0b598acc2e3a vp90-2-10-show-existing-frame-352x288-0004.i420
+63fa55ae9535ccdf06d44cce8065dda6 vp90-2-10-show-existing-frame-352x288-0005.i420
+a41f00034923e56ba51a0b598acc2e3a vp90-2-10-show-existing-frame-352x288-0006.i420
+0e4b08e14d919edee2bbff2ecd47de57 vp90-2-10-show-existing-frame-352x288-0007.i420
+0e4b08e14d919edee2bbff2ecd47de57 vp90-2-10-show-existing-frame-352x288-0008.i420
+5d4af03fc3d410413ef2b5a6275528b7 vp90-2-10-show-existing-frame-352x288-0009.i420
+9e932915c67a789f6877e6d3f76d3649 vp90-2-10-show-existing-frame-352x288-0010.i420
+12f2e975c217e7ffcf334524e8acec35 vp90-2-10-show-existing-frame-352x288-0011.i420
+9e932915c67a789f6877e6d3f76d3649 vp90-2-10-show-existing-frame-352x288-0012.i420
+12f2e975c217e7ffcf334524e8acec35 vp90-2-10-show-existing-frame-352x288-0013.i420
diff --git a/tests/tests/media/res/raw/vp90_2_12_droppable_1.vp9 b/tests/tests/media/res/raw/vp90_2_12_droppable_1.vp9
new file mode 100644
index 0000000..666d187
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_12_droppable_1.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_12_droppable_1_vp9_md5 b/tests/tests/media/res/raw/vp90_2_12_droppable_1_vp9_md5
new file mode 100644
index 0000000..7b1abf8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_12_droppable_1_vp9_md5
@@ -0,0 +1,99 @@
+1839e5db94dc99681d690d544cbe28a4 vp90-2-12-droppable_1.ivf-352x288-0001.i420
+dae2db51b91745edddb33ddbeb4e0988 vp90-2-12-droppable_1.ivf-352x288-0002.i420
+046639dbef310bf9016a54498a3ef0a3 vp90-2-12-droppable_1.ivf-352x288-0003.i420
+947044a5dbc918e8be468c2bc9eaeeaa vp90-2-12-droppable_1.ivf-352x288-0004.i420
+f96322ba3bf86065829d15c4394a1ab2 vp90-2-12-droppable_1.ivf-352x288-0005.i420
+4dfcf05608b399d56b0b29e3447ac24a vp90-2-12-droppable_1.ivf-352x288-0006.i420
+b772fd5f5e3221d9c1daf690aeca89e8 vp90-2-12-droppable_1.ivf-352x288-0007.i420
+d8838cf1a4316c6c9ba7f42f8cba205c vp90-2-12-droppable_1.ivf-352x288-0008.i420
+368f762830ed3d29d642798ff88107bd vp90-2-12-droppable_1.ivf-352x288-0009.i420
+f3e614a8f67681f814242c75e6ac66f7 vp90-2-12-droppable_1.ivf-352x288-0010.i420
+f49458a915dd853e53c15e52e280085b vp90-2-12-droppable_1.ivf-352x288-0011.i420
+65cbd3f3f8447d3caf935cddfcb6cb15 vp90-2-12-droppable_1.ivf-352x288-0012.i420
+8f4764c45093050a78b4b6055648cda0 vp90-2-12-droppable_1.ivf-352x288-0013.i420
+16d399bff977cdac0543daffba3a14bd vp90-2-12-droppable_1.ivf-352x288-0014.i420
+59f16bc632697d20514a55814cf0a9ae vp90-2-12-droppable_1.ivf-352x288-0015.i420
+058ba53139a3f48883ae4e668177d564 vp90-2-12-droppable_1.ivf-352x288-0016.i420
+85796d9edf6a5fe5d0c804e8b80f4469 vp90-2-12-droppable_1.ivf-352x288-0017.i420
+94b7bf54b3dd8d007cb932c330e4e7cf vp90-2-12-droppable_1.ivf-352x288-0018.i420
+964732ac0abf132fe8c65a845eeaea39 vp90-2-12-droppable_1.ivf-352x288-0019.i420
+dda8408b95868ea683f921e88ca0f8f4 vp90-2-12-droppable_1.ivf-352x288-0020.i420
+33b008d0b3932abd28d1c0d484a89cb0 vp90-2-12-droppable_1.ivf-352x288-0021.i420
+bbf8f8edda10ab20cde304b362f6fc7c vp90-2-12-droppable_1.ivf-352x288-0022.i420
+6a08c9c1d4444f6b706a9193823e4866 vp90-2-12-droppable_1.ivf-352x288-0023.i420
+f3cfb225730f103c76083220b55aaf7e vp90-2-12-droppable_1.ivf-352x288-0024.i420
+aa43de9fd852ffca405f9e1be0c517b9 vp90-2-12-droppable_1.ivf-352x288-0025.i420
+e5bcd2084c06d7e391af0710a3f56f86 vp90-2-12-droppable_1.ivf-352x288-0026.i420
+e16276389746853039a5c1353e3f830e vp90-2-12-droppable_1.ivf-352x288-0027.i420
+8ecf32a7649dd9df718b5a31512aa17b vp90-2-12-droppable_1.ivf-352x288-0028.i420
+db63be2b267a77061f40a48a5ad94129 vp90-2-12-droppable_1.ivf-352x288-0029.i420
+94c6a699e9b5382e1e4a30d462d1b05d vp90-2-12-droppable_1.ivf-352x288-0030.i420
+340102d21a9c8d9119aed97d7bd408ba vp90-2-12-droppable_1.ivf-352x288-0031.i420
+a369b32d71a6daf9a589614cba76d06c vp90-2-12-droppable_1.ivf-352x288-0032.i420
+7c6f24525d07f08cfaaf8b57c1b1e0c7 vp90-2-12-droppable_1.ivf-352x288-0033.i420
+f99b35baf3e4f3967ad08b5475041959 vp90-2-12-droppable_1.ivf-352x288-0034.i420
+b1dede9bbe4a9542d10e7e2dcc225208 vp90-2-12-droppable_1.ivf-352x288-0035.i420
+d627915070dd5e6e11d1dff7b1dc4243 vp90-2-12-droppable_1.ivf-352x288-0036.i420
+2f176951d8716e1ac316f30388be269d vp90-2-12-droppable_1.ivf-352x288-0037.i420
+215828b89c294b2568a575438c75d4e0 vp90-2-12-droppable_1.ivf-352x288-0038.i420
+3a29b4bf698713cbd575e6b14257fc87 vp90-2-12-droppable_1.ivf-352x288-0039.i420
+b930a1eef6838edc9abb769909b87cd9 vp90-2-12-droppable_1.ivf-352x288-0040.i420
+532c260abbd6d1181be3ff7a77f2d350 vp90-2-12-droppable_1.ivf-352x288-0041.i420
+b9ee7c0ab6c7cf8881fe5ed165454638 vp90-2-12-droppable_1.ivf-352x288-0042.i420
+d516f6949c3704ab9f154e3720f5f9ec vp90-2-12-droppable_1.ivf-352x288-0043.i420
+bf05478086e97057856c3c987b220958 vp90-2-12-droppable_1.ivf-352x288-0044.i420
+92202af7ea355a8d4678e618c0344134 vp90-2-12-droppable_1.ivf-352x288-0045.i420
+ca870c59afab60c5da07e688a89be1a9 vp90-2-12-droppable_1.ivf-352x288-0046.i420
+92429a1763b07d2a0bf843a2953fcc1c vp90-2-12-droppable_1.ivf-352x288-0047.i420
+1614a4655799cd08875b1271767ce85e vp90-2-12-droppable_1.ivf-352x288-0048.i420
+2b30362c459109cafcff5f1bb8217e34 vp90-2-12-droppable_1.ivf-352x288-0049.i420
+6568f3dd687762489b7fd2c4a59dd38c vp90-2-12-droppable_1.ivf-352x288-0050.i420
+6121d029cf4e402f9999a6719b3d6d97 vp90-2-12-droppable_1.ivf-352x288-0051.i420
+085cc85c56e35b4a19b48b502d606ffb vp90-2-12-droppable_1.ivf-352x288-0052.i420
+63a7dc5d70bd142cb167c20f645a90bb vp90-2-12-droppable_1.ivf-352x288-0053.i420
+b3ae931ee6f2724304f6a67070a386c0 vp90-2-12-droppable_1.ivf-352x288-0054.i420
+07fcd2b18c1c8a6c46151acff26ce2c0 vp90-2-12-droppable_1.ivf-352x288-0055.i420
+658758a58b92693bafeff41a2424e2a9 vp90-2-12-droppable_1.ivf-352x288-0056.i420
+3619120dfca7b24434ebe8e87936996c vp90-2-12-droppable_1.ivf-352x288-0057.i420
+17152bbf314be8c30837cbece6fb53cd vp90-2-12-droppable_1.ivf-352x288-0058.i420
+bc3352c6948fac5a681bf37abcc9b8b4 vp90-2-12-droppable_1.ivf-352x288-0059.i420
+5a4e0a19a7653a5ad120b1f46f9905b4 vp90-2-12-droppable_1.ivf-352x288-0060.i420
+2632db035652049f5340d1e59d577d42 vp90-2-12-droppable_1.ivf-352x288-0061.i420
+95a28f288602ae1f859a02055103aa39 vp90-2-12-droppable_1.ivf-352x288-0062.i420
+3d01e40359a3cfca996908d331492848 vp90-2-12-droppable_1.ivf-352x288-0063.i420
+4b6243114b09dbf590c1250419327b01 vp90-2-12-droppable_1.ivf-352x288-0064.i420
+f9aae29d9168366933f2bcc57a5afcb8 vp90-2-12-droppable_1.ivf-352x288-0065.i420
+6bca12015a807fdf48cda90cbe042ab4 vp90-2-12-droppable_1.ivf-352x288-0066.i420
+7769b6fa16f8c09973d1a2c08cf18dbb vp90-2-12-droppable_1.ivf-352x288-0067.i420
+3457395b67960b1566007e764b0c0e81 vp90-2-12-droppable_1.ivf-352x288-0068.i420
+0d0ea9bdd5c4b164bbefc31000a28e49 vp90-2-12-droppable_1.ivf-352x288-0069.i420
+9fb6b2afb53b73a658b579beb3008bcd vp90-2-12-droppable_1.ivf-352x288-0070.i420
+c9a941b87dcdd09afaab68cca0ed668a vp90-2-12-droppable_1.ivf-352x288-0071.i420
+9a2baa4c442f3ebdf251e9bbef0dbf83 vp90-2-12-droppable_1.ivf-352x288-0072.i420
+ef90237bc4ed3d795ba78c8a4ef9f1d6 vp90-2-12-droppable_1.ivf-352x288-0073.i420
+68cabdcf5d934e279f1c45207e983d43 vp90-2-12-droppable_1.ivf-352x288-0074.i420
+ac5d93877691c05bb581a10bfcd058e5 vp90-2-12-droppable_1.ivf-352x288-0075.i420
+c4e09feb0a88d765c7681c7d427eda87 vp90-2-12-droppable_1.ivf-352x288-0076.i420
+690734960471ab41d5cdf052be87bd30 vp90-2-12-droppable_1.ivf-352x288-0077.i420
+4abaaa7e31a3a6e30b242e42587363d5 vp90-2-12-droppable_1.ivf-352x288-0078.i420
+b9c46f294e7a23b608004ff8aa2b9ea3 vp90-2-12-droppable_1.ivf-352x288-0079.i420
+b6a6a0e45c30de0f03880f753b6e75de vp90-2-12-droppable_1.ivf-352x288-0080.i420
+c8725906463cb71ed8a64ba8af6a79be vp90-2-12-droppable_1.ivf-352x288-0081.i420
+d0e28c090e859834a33bc0867a0f7ed7 vp90-2-12-droppable_1.ivf-352x288-0082.i420
+1ad8bf201d9898d562631226a2ef85fa vp90-2-12-droppable_1.ivf-352x288-0083.i420
+962fe544b1a76bafe8a1b77cd64679ba vp90-2-12-droppable_1.ivf-352x288-0084.i420
+89f9a77223961cc5ad49a11913ff9774 vp90-2-12-droppable_1.ivf-352x288-0085.i420
+483782bf6d14bbb19c749d58b8535e3e vp90-2-12-droppable_1.ivf-352x288-0086.i420
+dfbe1b7ecc880ce5da758728f7375d63 vp90-2-12-droppable_1.ivf-352x288-0087.i420
+11a51b22418cc8dad57a20b37dd10630 vp90-2-12-droppable_1.ivf-352x288-0088.i420
+50b90506f9666ccb7dd94b6d59096489 vp90-2-12-droppable_1.ivf-352x288-0089.i420
+101294ecaff7edf5155ddc6cf3595021 vp90-2-12-droppable_1.ivf-352x288-0090.i420
+177e8f9d8aaf40b17d0b677133fc7955 vp90-2-12-droppable_1.ivf-352x288-0091.i420
+c029f78e758a27b8fc4214abf5ddad07 vp90-2-12-droppable_1.ivf-352x288-0092.i420
+45b6df0756e3f98218f4e9f0f33b1f13 vp90-2-12-droppable_1.ivf-352x288-0093.i420
+82d1fd8cc9fa0a072a0fc6177e7f8805 vp90-2-12-droppable_1.ivf-352x288-0094.i420
+bf6c3e8df105fdb82a614f8e8f6d68af vp90-2-12-droppable_1.ivf-352x288-0095.i420
+2e66eccd31c0e1792f3019c0a7b43af6 vp90-2-12-droppable_1.ivf-352x288-0096.i420
+d7eab4f351bd3c03e873b93afc9b7803 vp90-2-12-droppable_1.ivf-352x288-0097.i420
+f7bc200d54ec154779521311c54a22d1 vp90-2-12-droppable_1.ivf-352x288-0098.i420
+8e2624d762102b6dbe13b7cf20ee1708 vp90-2-12-droppable_1.ivf-352x288-0099.i420
diff --git a/tests/tests/media/res/raw/vp90_2_12_droppable_2.vp9 b/tests/tests/media/res/raw/vp90_2_12_droppable_2.vp9
new file mode 100644
index 0000000..672af0b
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_12_droppable_2.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_12_droppable_2_vp9_md5 b/tests/tests/media/res/raw/vp90_2_12_droppable_2_vp9_md5
new file mode 100644
index 0000000..4ee5724
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_12_droppable_2_vp9_md5
@@ -0,0 +1,99 @@
+1839e5db94dc99681d690d544cbe28a4 vp90-2-12-droppable_2.ivf-352x288-0001.i420
+dae2db51b91745edddb33ddbeb4e0988 vp90-2-12-droppable_2.ivf-352x288-0002.i420
+046639dbef310bf9016a54498a3ef0a3 vp90-2-12-droppable_2.ivf-352x288-0003.i420
+947044a5dbc918e8be468c2bc9eaeeaa vp90-2-12-droppable_2.ivf-352x288-0004.i420
+f96322ba3bf86065829d15c4394a1ab2 vp90-2-12-droppable_2.ivf-352x288-0005.i420
+4dfcf05608b399d56b0b29e3447ac24a vp90-2-12-droppable_2.ivf-352x288-0006.i420
+b772fd5f5e3221d9c1daf690aeca89e8 vp90-2-12-droppable_2.ivf-352x288-0007.i420
+d8838cf1a4316c6c9ba7f42f8cba205c vp90-2-12-droppable_2.ivf-352x288-0008.i420
+368f762830ed3d29d642798ff88107bd vp90-2-12-droppable_2.ivf-352x288-0009.i420
+f3e614a8f67681f814242c75e6ac66f7 vp90-2-12-droppable_2.ivf-352x288-0010.i420
+f49458a915dd853e53c15e52e280085b vp90-2-12-droppable_2.ivf-352x288-0011.i420
+65cbd3f3f8447d3caf935cddfcb6cb15 vp90-2-12-droppable_2.ivf-352x288-0012.i420
+8f4764c45093050a78b4b6055648cda0 vp90-2-12-droppable_2.ivf-352x288-0013.i420
+16d399bff977cdac0543daffba3a14bd vp90-2-12-droppable_2.ivf-352x288-0014.i420
+59f16bc632697d20514a55814cf0a9ae vp90-2-12-droppable_2.ivf-352x288-0015.i420
+058ba53139a3f48883ae4e668177d564 vp90-2-12-droppable_2.ivf-352x288-0016.i420
+85796d9edf6a5fe5d0c804e8b80f4469 vp90-2-12-droppable_2.ivf-352x288-0017.i420
+94b7bf54b3dd8d007cb932c330e4e7cf vp90-2-12-droppable_2.ivf-352x288-0018.i420
+964732ac0abf132fe8c65a845eeaea39 vp90-2-12-droppable_2.ivf-352x288-0019.i420
+dda8408b95868ea683f921e88ca0f8f4 vp90-2-12-droppable_2.ivf-352x288-0020.i420
+33b008d0b3932abd28d1c0d484a89cb0 vp90-2-12-droppable_2.ivf-352x288-0021.i420
+bbf8f8edda10ab20cde304b362f6fc7c vp90-2-12-droppable_2.ivf-352x288-0022.i420
+6a08c9c1d4444f6b706a9193823e4866 vp90-2-12-droppable_2.ivf-352x288-0023.i420
+f3cfb225730f103c76083220b55aaf7e vp90-2-12-droppable_2.ivf-352x288-0024.i420
+aa43de9fd852ffca405f9e1be0c517b9 vp90-2-12-droppable_2.ivf-352x288-0025.i420
+e5bcd2084c06d7e391af0710a3f56f86 vp90-2-12-droppable_2.ivf-352x288-0026.i420
+e16276389746853039a5c1353e3f830e vp90-2-12-droppable_2.ivf-352x288-0027.i420
+8ecf32a7649dd9df718b5a31512aa17b vp90-2-12-droppable_2.ivf-352x288-0028.i420
+db63be2b267a77061f40a48a5ad94129 vp90-2-12-droppable_2.ivf-352x288-0029.i420
+94c6a699e9b5382e1e4a30d462d1b05d vp90-2-12-droppable_2.ivf-352x288-0030.i420
+340102d21a9c8d9119aed97d7bd408ba vp90-2-12-droppable_2.ivf-352x288-0031.i420
+a369b32d71a6daf9a589614cba76d06c vp90-2-12-droppable_2.ivf-352x288-0032.i420
+7c6f24525d07f08cfaaf8b57c1b1e0c7 vp90-2-12-droppable_2.ivf-352x288-0033.i420
+f99b35baf3e4f3967ad08b5475041959 vp90-2-12-droppable_2.ivf-352x288-0034.i420
+b1dede9bbe4a9542d10e7e2dcc225208 vp90-2-12-droppable_2.ivf-352x288-0035.i420
+d627915070dd5e6e11d1dff7b1dc4243 vp90-2-12-droppable_2.ivf-352x288-0036.i420
+2f176951d8716e1ac316f30388be269d vp90-2-12-droppable_2.ivf-352x288-0037.i420
+215828b89c294b2568a575438c75d4e0 vp90-2-12-droppable_2.ivf-352x288-0038.i420
+3a29b4bf698713cbd575e6b14257fc87 vp90-2-12-droppable_2.ivf-352x288-0039.i420
+b930a1eef6838edc9abb769909b87cd9 vp90-2-12-droppable_2.ivf-352x288-0040.i420
+532c260abbd6d1181be3ff7a77f2d350 vp90-2-12-droppable_2.ivf-352x288-0041.i420
+b9ee7c0ab6c7cf8881fe5ed165454638 vp90-2-12-droppable_2.ivf-352x288-0042.i420
+d516f6949c3704ab9f154e3720f5f9ec vp90-2-12-droppable_2.ivf-352x288-0043.i420
+bf05478086e97057856c3c987b220958 vp90-2-12-droppable_2.ivf-352x288-0044.i420
+92202af7ea355a8d4678e618c0344134 vp90-2-12-droppable_2.ivf-352x288-0045.i420
+ca870c59afab60c5da07e688a89be1a9 vp90-2-12-droppable_2.ivf-352x288-0046.i420
+92429a1763b07d2a0bf843a2953fcc1c vp90-2-12-droppable_2.ivf-352x288-0047.i420
+1614a4655799cd08875b1271767ce85e vp90-2-12-droppable_2.ivf-352x288-0048.i420
+2b30362c459109cafcff5f1bb8217e34 vp90-2-12-droppable_2.ivf-352x288-0049.i420
+6568f3dd687762489b7fd2c4a59dd38c vp90-2-12-droppable_2.ivf-352x288-0050.i420
+6121d029cf4e402f9999a6719b3d6d97 vp90-2-12-droppable_2.ivf-352x288-0051.i420
+085cc85c56e35b4a19b48b502d606ffb vp90-2-12-droppable_2.ivf-352x288-0052.i420
+63a7dc5d70bd142cb167c20f645a90bb vp90-2-12-droppable_2.ivf-352x288-0053.i420
+b3ae931ee6f2724304f6a67070a386c0 vp90-2-12-droppable_2.ivf-352x288-0054.i420
+07fcd2b18c1c8a6c46151acff26ce2c0 vp90-2-12-droppable_2.ivf-352x288-0055.i420
+658758a58b92693bafeff41a2424e2a9 vp90-2-12-droppable_2.ivf-352x288-0056.i420
+3619120dfca7b24434ebe8e87936996c vp90-2-12-droppable_2.ivf-352x288-0057.i420
+17152bbf314be8c30837cbece6fb53cd vp90-2-12-droppable_2.ivf-352x288-0058.i420
+bc3352c6948fac5a681bf37abcc9b8b4 vp90-2-12-droppable_2.ivf-352x288-0059.i420
+5a4e0a19a7653a5ad120b1f46f9905b4 vp90-2-12-droppable_2.ivf-352x288-0060.i420
+2632db035652049f5340d1e59d577d42 vp90-2-12-droppable_2.ivf-352x288-0061.i420
+95a28f288602ae1f859a02055103aa39 vp90-2-12-droppable_2.ivf-352x288-0062.i420
+3d01e40359a3cfca996908d331492848 vp90-2-12-droppable_2.ivf-352x288-0063.i420
+4b6243114b09dbf590c1250419327b01 vp90-2-12-droppable_2.ivf-352x288-0064.i420
+f9aae29d9168366933f2bcc57a5afcb8 vp90-2-12-droppable_2.ivf-352x288-0065.i420
+6bca12015a807fdf48cda90cbe042ab4 vp90-2-12-droppable_2.ivf-352x288-0066.i420
+7769b6fa16f8c09973d1a2c08cf18dbb vp90-2-12-droppable_2.ivf-352x288-0067.i420
+3457395b67960b1566007e764b0c0e81 vp90-2-12-droppable_2.ivf-352x288-0068.i420
+0d0ea9bdd5c4b164bbefc31000a28e49 vp90-2-12-droppable_2.ivf-352x288-0069.i420
+9fb6b2afb53b73a658b579beb3008bcd vp90-2-12-droppable_2.ivf-352x288-0070.i420
+c9a941b87dcdd09afaab68cca0ed668a vp90-2-12-droppable_2.ivf-352x288-0071.i420
+9a2baa4c442f3ebdf251e9bbef0dbf83 vp90-2-12-droppable_2.ivf-352x288-0072.i420
+ef90237bc4ed3d795ba78c8a4ef9f1d6 vp90-2-12-droppable_2.ivf-352x288-0073.i420
+68cabdcf5d934e279f1c45207e983d43 vp90-2-12-droppable_2.ivf-352x288-0074.i420
+ac5d93877691c05bb581a10bfcd058e5 vp90-2-12-droppable_2.ivf-352x288-0075.i420
+c4e09feb0a88d765c7681c7d427eda87 vp90-2-12-droppable_2.ivf-352x288-0076.i420
+690734960471ab41d5cdf052be87bd30 vp90-2-12-droppable_2.ivf-352x288-0077.i420
+4abaaa7e31a3a6e30b242e42587363d5 vp90-2-12-droppable_2.ivf-352x288-0078.i420
+b9c46f294e7a23b608004ff8aa2b9ea3 vp90-2-12-droppable_2.ivf-352x288-0079.i420
+b6a6a0e45c30de0f03880f753b6e75de vp90-2-12-droppable_2.ivf-352x288-0080.i420
+c8725906463cb71ed8a64ba8af6a79be vp90-2-12-droppable_2.ivf-352x288-0081.i420
+d0e28c090e859834a33bc0867a0f7ed7 vp90-2-12-droppable_2.ivf-352x288-0082.i420
+1ad8bf201d9898d562631226a2ef85fa vp90-2-12-droppable_2.ivf-352x288-0083.i420
+962fe544b1a76bafe8a1b77cd64679ba vp90-2-12-droppable_2.ivf-352x288-0084.i420
+89f9a77223961cc5ad49a11913ff9774 vp90-2-12-droppable_2.ivf-352x288-0085.i420
+483782bf6d14bbb19c749d58b8535e3e vp90-2-12-droppable_2.ivf-352x288-0086.i420
+dfbe1b7ecc880ce5da758728f7375d63 vp90-2-12-droppable_2.ivf-352x288-0087.i420
+11a51b22418cc8dad57a20b37dd10630 vp90-2-12-droppable_2.ivf-352x288-0088.i420
+50b90506f9666ccb7dd94b6d59096489 vp90-2-12-droppable_2.ivf-352x288-0089.i420
+101294ecaff7edf5155ddc6cf3595021 vp90-2-12-droppable_2.ivf-352x288-0090.i420
+177e8f9d8aaf40b17d0b677133fc7955 vp90-2-12-droppable_2.ivf-352x288-0091.i420
+c029f78e758a27b8fc4214abf5ddad07 vp90-2-12-droppable_2.ivf-352x288-0092.i420
+45b6df0756e3f98218f4e9f0f33b1f13 vp90-2-12-droppable_2.ivf-352x288-0093.i420
+82d1fd8cc9fa0a072a0fc6177e7f8805 vp90-2-12-droppable_2.ivf-352x288-0094.i420
+bf6c3e8df105fdb82a614f8e8f6d68af vp90-2-12-droppable_2.ivf-352x288-0095.i420
+2e66eccd31c0e1792f3019c0a7b43af6 vp90-2-12-droppable_2.ivf-352x288-0096.i420
+d7eab4f351bd3c03e873b93afc9b7803 vp90-2-12-droppable_2.ivf-352x288-0097.i420
+f7bc200d54ec154779521311c54a22d1 vp90-2-12-droppable_2.ivf-352x288-0098.i420
+8e2624d762102b6dbe13b7cf20ee1708 vp90-2-12-droppable_2.ivf-352x288-0099.i420
diff --git a/tests/tests/media/res/raw/vp90_2_12_droppable_3.vp9 b/tests/tests/media/res/raw/vp90_2_12_droppable_3.vp9
new file mode 100644
index 0000000..1f26178
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_12_droppable_3.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_12_droppable_3_vp9_md5 b/tests/tests/media/res/raw/vp90_2_12_droppable_3_vp9_md5
new file mode 100644
index 0000000..9fdb07c
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_12_droppable_3_vp9_md5
@@ -0,0 +1,31 @@
+7ab6428314a7bce2ebae83b78acf9d1c vp90-2-12-droppable_3.ivf-640x480-0001.i420
+373cfc7765ea8038e64d95ff90b6d9e8 vp90-2-12-droppable_3.ivf-640x480-0002.i420
+58d782daf8249542df4a4f0e66994b86 vp90-2-12-droppable_3.ivf-640x480-0003.i420
+38b13b37c460f67dbbda8847a37e5a58 vp90-2-12-droppable_3.ivf-640x480-0004.i420
+902d00e196093fcebad74ef608d7c3ff vp90-2-12-droppable_3.ivf-640x480-0005.i420
+f3549650a4581de21916b189576b6a52 vp90-2-12-droppable_3.ivf-640x480-0006.i420
+a44d4bf06a241f31d1755ff6a118060a vp90-2-12-droppable_3.ivf-640x480-0007.i420
+8eeef076eec9eec2861f3376ebf87d0a vp90-2-12-droppable_3.ivf-640x480-0008.i420
+9a81bf95fc7210526b79c47ff80ae968 vp90-2-12-droppable_3.ivf-640x480-0009.i420
+bf215dfd9b764292de4d064389015e55 vp90-2-12-droppable_3.ivf-640x480-0010.i420
+283b1efdedde5633606d8a5d68097768 vp90-2-12-droppable_3.ivf-640x480-0011.i420
+dbb74ee6ec5f32b9ecb58b73d465be26 vp90-2-12-droppable_3.ivf-640x480-0012.i420
+ca1e21e458f674036addf08a79f6164e vp90-2-12-droppable_3.ivf-640x480-0013.i420
+24c3b279ecb0559ac146abed5976c54a vp90-2-12-droppable_3.ivf-640x480-0014.i420
+5f6796e3fa0e85d65b46ba66932ee09c vp90-2-12-droppable_3.ivf-640x480-0015.i420
+7b22b5642e42e79fcc339ca6652f8f39 vp90-2-12-droppable_3.ivf-640x480-0016.i420
+7478595483ce62a5906f979ad296b6c5 vp90-2-12-droppable_3.ivf-640x480-0017.i420
+55d843f54af65305f7e298013e90a839 vp90-2-12-droppable_3.ivf-640x480-0018.i420
+6ab0a82b5f0736d951b58f2245adb793 vp90-2-12-droppable_3.ivf-640x480-0019.i420
+1a9f6adde0d6ecd7bc83301ffeb15e51 vp90-2-12-droppable_3.ivf-640x480-0020.i420
+07552d44c99801657a3301d50c6d3897 vp90-2-12-droppable_3.ivf-640x480-0021.i420
+e9cdeec3accd4d19aa199a64e6cd163d vp90-2-12-droppable_3.ivf-640x480-0022.i420
+5dedc5eeb214bc4356bfa53e1c00d723 vp90-2-12-droppable_3.ivf-640x480-0023.i420
+dfd4bf2f664b46c36de24edf799c5c2a vp90-2-12-droppable_3.ivf-640x480-0024.i420
+deb33fefe4f20f09b6e84a037a7c2755 vp90-2-12-droppable_3.ivf-640x480-0025.i420
+e7425d6d380be060a89a2ca85660042f vp90-2-12-droppable_3.ivf-640x480-0026.i420
+74e3b4f750566b09c2fd0baafa5d69d1 vp90-2-12-droppable_3.ivf-640x480-0027.i420
+dd9f990aa7d858290a970be4681b7a1f vp90-2-12-droppable_3.ivf-640x480-0028.i420
+f7e8c6e20722b6a69e7f6766f41f2805 vp90-2-12-droppable_3.ivf-640x480-0029.i420
+835fca0a38539ef2632f85a051544326 vp90-2-12-droppable_3.ivf-640x480-0030.i420
+9c10a225363aa167ccef6e53b19ee64f vp90-2-12-droppable_3.ivf-640x480-0031.i420
diff --git a/tests/tests/media/res/raw/vp90_2_15_segkey.vp9 b/tests/tests/media/res/raw/vp90_2_15_segkey.vp9
new file mode 100644
index 0000000..b67d891
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_15_segkey.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_15_segkey_adpq.vp9 b/tests/tests/media/res/raw/vp90_2_15_segkey_adpq.vp9
new file mode 100644
index 0000000..9e54de9
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_15_segkey_adpq.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_15_segkey_adpq_vp9_md5 b/tests/tests/media/res/raw/vp90_2_15_segkey_adpq_vp9_md5
new file mode 100644
index 0000000..e3ee4d7
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_15_segkey_adpq_vp9_md5
@@ -0,0 +1,150 @@
+d4f0e4b606ddb40b482aecb24cf3bc63 vp90-2-15-segkey_adpq.webm-1280x720-0001.i420
+692ec092bc5928fa6430d056e883759a vp90-2-15-segkey_adpq.webm-1280x720-0002.i420
+dad790df33430899fed98886a24b37e5 vp90-2-15-segkey_adpq.webm-1280x720-0003.i420
+7e66e793ac9462a40dd5b963fb62e667 vp90-2-15-segkey_adpq.webm-1280x720-0004.i420
+0d795c6e20f42f09aca0ddb9dffaa6e8 vp90-2-15-segkey_adpq.webm-1280x720-0005.i420
+0ef3739c4ab2c51f0ab8e290eadad77e vp90-2-15-segkey_adpq.webm-1280x720-0006.i420
+04a15f765960263c1b4a5a8822e17322 vp90-2-15-segkey_adpq.webm-1280x720-0007.i420
+116d518830c958bf46759fd79bc74198 vp90-2-15-segkey_adpq.webm-1280x720-0008.i420
+58ea67addab05825cc2e5f2ab99fca4b vp90-2-15-segkey_adpq.webm-1280x720-0009.i420
+590f6e5deea6dde21dc1098fa2017c2f vp90-2-15-segkey_adpq.webm-1280x720-0010.i420
+895479957b0882ccce4159782dee8deb vp90-2-15-segkey_adpq.webm-1280x720-0011.i420
+cc8e05afdfb6f9c7042fd6f9e9d49140 vp90-2-15-segkey_adpq.webm-1280x720-0012.i420
+3e47c556a63af90f1ca4609f97f25d2c vp90-2-15-segkey_adpq.webm-1280x720-0013.i420
+e5ca5dce8cbd39412db2fe219d6d2594 vp90-2-15-segkey_adpq.webm-1280x720-0014.i420
+c62b456e12230660d26eb7226f257d0c vp90-2-15-segkey_adpq.webm-1280x720-0015.i420
+e184c961b373de465d3242f32f7cf3ed vp90-2-15-segkey_adpq.webm-1280x720-0016.i420
+7466b91858f740fc28965a63effe05d6 vp90-2-15-segkey_adpq.webm-1280x720-0017.i420
+c8f06a3b1e471c4e7a9efd71a30dfe3b vp90-2-15-segkey_adpq.webm-1280x720-0018.i420
+d4fb95148963b2eaff0211ddc5117c13 vp90-2-15-segkey_adpq.webm-1280x720-0019.i420
+c646526b40277289520d47ed8ca3b644 vp90-2-15-segkey_adpq.webm-1280x720-0020.i420
+e441ae686fa444e4e3584543611043ba vp90-2-15-segkey_adpq.webm-1280x720-0021.i420
+68d707ef6909bfbc02dcbd9e392a04f6 vp90-2-15-segkey_adpq.webm-1280x720-0022.i420
+1ff285d17a26622b61bd2651754602b1 vp90-2-15-segkey_adpq.webm-1280x720-0023.i420
+c272192987e44e54e5335e6416bd15a5 vp90-2-15-segkey_adpq.webm-1280x720-0024.i420
+8f6f02572181eb4855dcd4c957e57d2e vp90-2-15-segkey_adpq.webm-1280x720-0025.i420
+baf03eb567fd092eeb6f08ff5e098350 vp90-2-15-segkey_adpq.webm-1280x720-0026.i420
+479c78bd3da0892b8d4e32c99ec4739f vp90-2-15-segkey_adpq.webm-1280x720-0027.i420
+d39a52f6e30ef10462bdef1006809e88 vp90-2-15-segkey_adpq.webm-1280x720-0028.i420
+d58395369806221efe9ba88513319d8a vp90-2-15-segkey_adpq.webm-1280x720-0029.i420
+459e77e83c510ee1d79bf069752d44e5 vp90-2-15-segkey_adpq.webm-1280x720-0030.i420
+438027c8eacb9c795f8267a151ef5a4e vp90-2-15-segkey_adpq.webm-1280x720-0031.i420
+ea6b73fb0d4b23ebbdaeb0267135d083 vp90-2-15-segkey_adpq.webm-1280x720-0032.i420
+48160c624d4d5050a4c8abcbe0edf4b2 vp90-2-15-segkey_adpq.webm-1280x720-0033.i420
+6fc6d5b4751cf137fc0204c0026f2503 vp90-2-15-segkey_adpq.webm-1280x720-0034.i420
+5ea20f6483fc5cde854313ed8288c7ca vp90-2-15-segkey_adpq.webm-1280x720-0035.i420
+dafa41fa3468f684ca5538593cd1a0de vp90-2-15-segkey_adpq.webm-1280x720-0036.i420
+b73d3336c83a27874e24b691c34c3421 vp90-2-15-segkey_adpq.webm-1280x720-0037.i420
+d0b0488a5871a49442746ac8ea1343bc vp90-2-15-segkey_adpq.webm-1280x720-0038.i420
+df6fe9cb354624b69908730f24f51b88 vp90-2-15-segkey_adpq.webm-1280x720-0039.i420
+a388b159a024ace9437976206e62473c vp90-2-15-segkey_adpq.webm-1280x720-0040.i420
+9007423410201a70b6997477ed9040f6 vp90-2-15-segkey_adpq.webm-1280x720-0041.i420
+7f7425cc018ad391e06b867f51d69513 vp90-2-15-segkey_adpq.webm-1280x720-0042.i420
+2ef51a3a15c627f803eee7f351cdfa4e vp90-2-15-segkey_adpq.webm-1280x720-0043.i420
+260cded2461ab87181d650c58a8a0656 vp90-2-15-segkey_adpq.webm-1280x720-0044.i420
+fdd7a93b5f25ec2b74d93736fa7bb475 vp90-2-15-segkey_adpq.webm-1280x720-0045.i420
+810bb95ef0221b50ef12c7d0a4740fec vp90-2-15-segkey_adpq.webm-1280x720-0046.i420
+f7eb4d63c16aebfeba4804c4e9c2c134 vp90-2-15-segkey_adpq.webm-1280x720-0047.i420
+a1ae94b85bced552e2c4f15ab5c5096d vp90-2-15-segkey_adpq.webm-1280x720-0048.i420
+4b7b9e460b4a4ceab5deb5c6876cea05 vp90-2-15-segkey_adpq.webm-1280x720-0049.i420
+514472399dc39fcc4e833e166b81ea8e vp90-2-15-segkey_adpq.webm-1280x720-0050.i420
+dca73ca76936d0a7eeb71c20955ea3a3 vp90-2-15-segkey_adpq.webm-1280x720-0051.i420
+927b185567b515a6bd102e1199ee1836 vp90-2-15-segkey_adpq.webm-1280x720-0052.i420
+63e1fffd59b77c53811d75a116fbac60 vp90-2-15-segkey_adpq.webm-1280x720-0053.i420
+5ca302497e81d564cfd455e2b606b262 vp90-2-15-segkey_adpq.webm-1280x720-0054.i420
+6e317d469ee664bc511a8286650f0b79 vp90-2-15-segkey_adpq.webm-1280x720-0055.i420
+d93e1909f3bdda983e0b3c73a8c51754 vp90-2-15-segkey_adpq.webm-1280x720-0056.i420
+836072cb1c4dc3dc32c935ba4ac3f716 vp90-2-15-segkey_adpq.webm-1280x720-0057.i420
+014e61666ba819260a25f09ae97768a8 vp90-2-15-segkey_adpq.webm-1280x720-0058.i420
+997fa6283e48ff017ce04041b9022fb9 vp90-2-15-segkey_adpq.webm-1280x720-0059.i420
+b2c35749c6b848601193c2eff7f0bdf1 vp90-2-15-segkey_adpq.webm-1280x720-0060.i420
+813e9f562ef53589afbfe7d73002c136 vp90-2-15-segkey_adpq.webm-1280x720-0061.i420
+be876a05cfc72fe6138e1c24b6e94c3f vp90-2-15-segkey_adpq.webm-1280x720-0062.i420
+2a33b99f67fe5579ddbd62bac085ae8a vp90-2-15-segkey_adpq.webm-1280x720-0063.i420
+8d374a1886861cfd9ca6f16a0aff1b6c vp90-2-15-segkey_adpq.webm-1280x720-0064.i420
+eff4e17b08c67a1663c8f1cc614bd94a vp90-2-15-segkey_adpq.webm-1280x720-0065.i420
+39e4d97460cf02ecfbc666e0413d7db1 vp90-2-15-segkey_adpq.webm-1280x720-0066.i420
+732f41606146dfb0c6a8cf130df969a8 vp90-2-15-segkey_adpq.webm-1280x720-0067.i420
+9b724b808bc26f21aaa32653185b2cf3 vp90-2-15-segkey_adpq.webm-1280x720-0068.i420
+e18598cb7ac70cdb5dea29b35ae5accb vp90-2-15-segkey_adpq.webm-1280x720-0069.i420
+afbcad9f7bad0b58a5bccdb8977a60fb vp90-2-15-segkey_adpq.webm-1280x720-0070.i420
+6ec24c40cd8a0cf2e15339ce4f60c232 vp90-2-15-segkey_adpq.webm-1280x720-0071.i420
+76616dbe8207235f6890360566f9e8df vp90-2-15-segkey_adpq.webm-1280x720-0072.i420
+49a5c751ed430e9bc41c3a3334295025 vp90-2-15-segkey_adpq.webm-1280x720-0073.i420
+f657e47dbbcc2a04e9e7b71ecd8451ff vp90-2-15-segkey_adpq.webm-1280x720-0074.i420
+8e85f3d26b26f26ccd804061d2f37bbb vp90-2-15-segkey_adpq.webm-1280x720-0075.i420
+5a9dd5c0390491cd21163da01dc21f4d vp90-2-15-segkey_adpq.webm-1280x720-0076.i420
+3cf88ad2d2d7ecf1223afa5d1b849317 vp90-2-15-segkey_adpq.webm-1280x720-0077.i420
+27385b23461b5f1c137c2f29354595ed vp90-2-15-segkey_adpq.webm-1280x720-0078.i420
+e6eacbe2890389c586f2936a75ab3509 vp90-2-15-segkey_adpq.webm-1280x720-0079.i420
+19a48ffafdcdb6fb1d6b9808daed2f86 vp90-2-15-segkey_adpq.webm-1280x720-0080.i420
+f8c9419d4944fb214e06a2c30a560d93 vp90-2-15-segkey_adpq.webm-1280x720-0081.i420
+3f3d3dd54e5aa6bd59af1be86ec9be3d vp90-2-15-segkey_adpq.webm-1280x720-0082.i420
+28be5316ed79dc47b6a142cef0c16ab7 vp90-2-15-segkey_adpq.webm-1280x720-0083.i420
+6fbed684bfe8dfd354210293d7eb4d0b vp90-2-15-segkey_adpq.webm-1280x720-0084.i420
+e60cd76f68c95f8b484d0b6424eea4cc vp90-2-15-segkey_adpq.webm-1280x720-0085.i420
+e05a0cf382f49039faddaffeff2cec16 vp90-2-15-segkey_adpq.webm-1280x720-0086.i420
+42ea736ebbfe50f1ebd460d71781e5d6 vp90-2-15-segkey_adpq.webm-1280x720-0087.i420
+80f78066700b6752bbc1a41390ddb482 vp90-2-15-segkey_adpq.webm-1280x720-0088.i420
+14671354929fcf10677b2ed2db3c8cb4 vp90-2-15-segkey_adpq.webm-1280x720-0089.i420
+96a7d68407f1a2c96bd3cafe0c696bf5 vp90-2-15-segkey_adpq.webm-1280x720-0090.i420
+2f2adb990cfa42229db987a668b19d38 vp90-2-15-segkey_adpq.webm-1280x720-0091.i420
+a8233951004e1bb0d0937435a517fad2 vp90-2-15-segkey_adpq.webm-1280x720-0092.i420
+6163e872c38adfde7b0c8891cbb2c969 vp90-2-15-segkey_adpq.webm-1280x720-0093.i420
+990165e0905fb80ccc29d2de062d4f9b vp90-2-15-segkey_adpq.webm-1280x720-0094.i420
+e6f3224c4c60098ee93fca870f8636b2 vp90-2-15-segkey_adpq.webm-1280x720-0095.i420
+8c561667345f932618f8b3aaa43ffde0 vp90-2-15-segkey_adpq.webm-1280x720-0096.i420
+1acb3999bacd483d1153beb43ee09772 vp90-2-15-segkey_adpq.webm-1280x720-0097.i420
+2a075c7bc49190df83b8285ee6e124d3 vp90-2-15-segkey_adpq.webm-1280x720-0098.i420
+890a134a3c77d9b64d83fe6d2def02de vp90-2-15-segkey_adpq.webm-1280x720-0099.i420
+d0b41422b89f03ffcbde7c85889ad2c2 vp90-2-15-segkey_adpq.webm-1280x720-0100.i420
+fdc4f855d70ef16ec9baeb05c3a73f44 vp90-2-15-segkey_adpq.webm-1280x720-0101.i420
+ed9f847a3b4280cfe306018825c76508 vp90-2-15-segkey_adpq.webm-1280x720-0102.i420
+5deb2536bba158c722bc0d909f45e611 vp90-2-15-segkey_adpq.webm-1280x720-0103.i420
+fc7880ca8680e03fb1978adce8066027 vp90-2-15-segkey_adpq.webm-1280x720-0104.i420
+6e1c351c6b102e9185f688a02190b87f vp90-2-15-segkey_adpq.webm-1280x720-0105.i420
+1f6169bf490ed1b4c391383f770fec02 vp90-2-15-segkey_adpq.webm-1280x720-0106.i420
+80ac3b673b1504fb1e88d883a91a539c vp90-2-15-segkey_adpq.webm-1280x720-0107.i420
+d2e7654f961ff3767c1e9e8558c2f20d vp90-2-15-segkey_adpq.webm-1280x720-0108.i420
+365368d813eb10c5adc53e47afeb414d vp90-2-15-segkey_adpq.webm-1280x720-0109.i420
+5f74f55478377dd31da91cf195332480 vp90-2-15-segkey_adpq.webm-1280x720-0110.i420
+827b7b3853ea3b1855583b59ed7b09c2 vp90-2-15-segkey_adpq.webm-1280x720-0111.i420
+2017c1a57a271308172bd84d3887d063 vp90-2-15-segkey_adpq.webm-1280x720-0112.i420
+d65b95c71db9972dc051bec7df19f85f vp90-2-15-segkey_adpq.webm-1280x720-0113.i420
+7243da9072729ffa75209a6699e77ac3 vp90-2-15-segkey_adpq.webm-1280x720-0114.i420
+112da8d27907ab6a66b030e9c8864e46 vp90-2-15-segkey_adpq.webm-1280x720-0115.i420
+e2837b6409de4bc6e71ff9eca8eab391 vp90-2-15-segkey_adpq.webm-1280x720-0116.i420
+567eba2ddb91a02665ac96fa10703f00 vp90-2-15-segkey_adpq.webm-1280x720-0117.i420
+474a99d56fce0e7e96ac3585b905956f vp90-2-15-segkey_adpq.webm-1280x720-0118.i420
+3087edb09f1ef2e63130b7c03e696028 vp90-2-15-segkey_adpq.webm-1280x720-0119.i420
+574f7328da31760ecf237617aebd7784 vp90-2-15-segkey_adpq.webm-1280x720-0120.i420
+c3a7669bb496bec766a74a800275ff6c vp90-2-15-segkey_adpq.webm-1280x720-0121.i420
+c0d87245a92e7140e6b729c26fe97a95 vp90-2-15-segkey_adpq.webm-1280x720-0122.i420
+467e33e84435fe64cb14653600ec5163 vp90-2-15-segkey_adpq.webm-1280x720-0123.i420
+1c7a5b2472c00e9dc63f679b51ead6a9 vp90-2-15-segkey_adpq.webm-1280x720-0124.i420
+8fb7197463cdae6c45437a73dcb4a3d8 vp90-2-15-segkey_adpq.webm-1280x720-0125.i420
+f352fee36f51536175b05b5ff5a3187a vp90-2-15-segkey_adpq.webm-1280x720-0126.i420
+ac1ed4392a38268a2495508245032d74 vp90-2-15-segkey_adpq.webm-1280x720-0127.i420
+b8179a306c4fbc6f207d15acaae92dfb vp90-2-15-segkey_adpq.webm-1280x720-0128.i420
+7f263b0fd68652d83b75d24cc11c89e8 vp90-2-15-segkey_adpq.webm-1280x720-0129.i420
+39e33d02a01247cefe19d8bf9fbdecae vp90-2-15-segkey_adpq.webm-1280x720-0130.i420
+49a4e89c9fcc66f7e6e679aee4af0852 vp90-2-15-segkey_adpq.webm-1280x720-0131.i420
+0af52a32e6d74694a0a1f12aa78293fe vp90-2-15-segkey_adpq.webm-1280x720-0132.i420
+fedde75a5c093ea12f0ed328da7350c9 vp90-2-15-segkey_adpq.webm-1280x720-0133.i420
+2ab788cf689fdbe8fbc74dde165605ad vp90-2-15-segkey_adpq.webm-1280x720-0134.i420
+682c2316cbd2e8a5e54edd1e9309a6c7 vp90-2-15-segkey_adpq.webm-1280x720-0135.i420
+f155e8fa47625f18dffea813a7070c71 vp90-2-15-segkey_adpq.webm-1280x720-0136.i420
+2611eb2b2da8f6995ac2159012ec540a vp90-2-15-segkey_adpq.webm-1280x720-0137.i420
+a1130a4ddf7dbd592e23001c4b98b3fc vp90-2-15-segkey_adpq.webm-1280x720-0138.i420
+84eef6f47bff223c6a0916c0688d2f7c vp90-2-15-segkey_adpq.webm-1280x720-0139.i420
+ccfab0b84c7fc59d850ac5cb8d36da41 vp90-2-15-segkey_adpq.webm-1280x720-0140.i420
+6866845dfb320ecd9c22444ca7e52c8b vp90-2-15-segkey_adpq.webm-1280x720-0141.i420
+3068ceb83ee4d047df3880c64754efd7 vp90-2-15-segkey_adpq.webm-1280x720-0142.i420
+7f9a74e20cfe10972961e7f21529f7f4 vp90-2-15-segkey_adpq.webm-1280x720-0143.i420
+29156833963ec7f218d38fca7df132bf vp90-2-15-segkey_adpq.webm-1280x720-0144.i420
+f8feb4c2ae1ce371fc8b4a83d7dc34e0 vp90-2-15-segkey_adpq.webm-1280x720-0145.i420
+0e5fe8965da239c17b02f0c902feeaec vp90-2-15-segkey_adpq.webm-1280x720-0146.i420
+e8d37eb1b8c2576658ebc58a7cc6c0d4 vp90-2-15-segkey_adpq.webm-1280x720-0147.i420
+0a89fd2784112bbd54eb559a8272ab1e vp90-2-15-segkey_adpq.webm-1280x720-0148.i420
+342bc99cdd618272d12d045698b9cb20 vp90-2-15-segkey_adpq.webm-1280x720-0149.i420
+a489a32bb43559b8a1989b13660e3cf6 vp90-2-15-segkey_adpq.webm-1280x720-0150.i420
diff --git a/tests/tests/media/res/raw/vp90_2_15_segkey_vp9_md5 b/tests/tests/media/res/raw/vp90_2_15_segkey_vp9_md5
new file mode 100644
index 0000000..809e25e
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_15_segkey_vp9_md5
@@ -0,0 +1 @@
+d3805a0d832b9bdd69ad99d68490be7b vp90-2-15-segkey.webm-1280x720-0001.i420
diff --git a/tests/tests/media/res/raw/vp90_2_16_intra_only.vp9 b/tests/tests/media/res/raw/vp90_2_16_intra_only.vp9
new file mode 100644
index 0000000..a88750f
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_16_intra_only.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_16_intra_only_vp9_md5 b/tests/tests/media/res/raw/vp90_2_16_intra_only_vp9_md5
new file mode 100644
index 0000000..112a52a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_16_intra_only_vp9_md5
@@ -0,0 +1,7 @@
+d57529601178948afa4818c3c8938884 vp90-2-16-intra-only-352x288-0001.i420
+d47e00250c45733d64af067a417bcd06 vp90-2-16-intra-only-352x288-0002.i420
+984e41cd8350808ac6129746b2377818 vp90-2-16-intra-only-352x288-0003.i420
+a5fa62996b4bb52e72e335722cf55bef vp90-2-16-intra-only-352x288-0004.i420
+b71ca5ad650170ac921a71a6440fb508 vp90-2-16-intra-only-352x288-0005.i420
+76ba63001170b8992fc72be5c4ace731 vp90-2-16-intra-only-352x288-0006.i420
+c4e7f96a8fd58d901b1d881926ddae09 vp90-2-16-intra-only-352x288-0007.i420
diff --git a/tests/tests/media/res/raw/vp90_2_17_show_existing_frame.vp9 b/tests/tests/media/res/raw/vp90_2_17_show_existing_frame.vp9
new file mode 100644
index 0000000..4748eeb
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_17_show_existing_frame.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_17_show_existing_frame_vp9_md5 b/tests/tests/media/res/raw/vp90_2_17_show_existing_frame_vp9_md5
new file mode 100644
index 0000000..50394da
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_17_show_existing_frame_vp9_md5
@@ -0,0 +1,30 @@
+b71ca5ad650170ac921a71a6440fb508 vp90-2-17-show-existing-frame.webm-352x288-0001.i420
+edc30ba14b73198ca827c1b216957dec vp90-2-17-show-existing-frame.webm-352x288-0002.i420
+1902c5b3a82f6bdeb80a5b053909df04 vp90-2-17-show-existing-frame.webm-352x288-0003.i420
+9a96e33ed546d7961c6e5bc48244a5c7 vp90-2-17-show-existing-frame.webm-352x288-0004.i420
+b02a48630b0f3c08c61dd2518b55ea39 vp90-2-17-show-existing-frame.webm-352x288-0005.i420
+8ac9cec1101a46bf4ba20191b7ba3f07 vp90-2-17-show-existing-frame.webm-352x288-0006.i420
+88ea8c3cb9eca47152b5d22435a06675 vp90-2-17-show-existing-frame.webm-352x288-0007.i420
+bff3406209ec0d592a891dff2b58d6cd vp90-2-17-show-existing-frame.webm-352x288-0008.i420
+b71ca5ad650170ac921a71a6440fb508 vp90-2-17-show-existing-frame.webm-352x288-0009.i420
+edc30ba14b73198ca827c1b216957dec vp90-2-17-show-existing-frame.webm-352x288-0010.i420
+1902c5b3a82f6bdeb80a5b053909df04 vp90-2-17-show-existing-frame.webm-352x288-0011.i420
+9a96e33ed546d7961c6e5bc48244a5c7 vp90-2-17-show-existing-frame.webm-352x288-0012.i420
+b02a48630b0f3c08c61dd2518b55ea39 vp90-2-17-show-existing-frame.webm-352x288-0013.i420
+8ac9cec1101a46bf4ba20191b7ba3f07 vp90-2-17-show-existing-frame.webm-352x288-0014.i420
+88ea8c3cb9eca47152b5d22435a06675 vp90-2-17-show-existing-frame.webm-352x288-0015.i420
+bff3406209ec0d592a891dff2b58d6cd vp90-2-17-show-existing-frame.webm-352x288-0016.i420
+b71ca5ad650170ac921a71a6440fb508 vp90-2-17-show-existing-frame.webm-352x288-0017.i420
+edc30ba14b73198ca827c1b216957dec vp90-2-17-show-existing-frame.webm-352x288-0018.i420
+1902c5b3a82f6bdeb80a5b053909df04 vp90-2-17-show-existing-frame.webm-352x288-0019.i420
+9a96e33ed546d7961c6e5bc48244a5c7 vp90-2-17-show-existing-frame.webm-352x288-0020.i420
+b02a48630b0f3c08c61dd2518b55ea39 vp90-2-17-show-existing-frame.webm-352x288-0021.i420
+8ac9cec1101a46bf4ba20191b7ba3f07 vp90-2-17-show-existing-frame.webm-352x288-0022.i420
+88ea8c3cb9eca47152b5d22435a06675 vp90-2-17-show-existing-frame.webm-352x288-0023.i420
+bff3406209ec0d592a891dff2b58d6cd vp90-2-17-show-existing-frame.webm-352x288-0024.i420
+a36428fd889ddf9983638c581c1d9146 vp90-2-17-show-existing-frame.webm-352x288-0025.i420
+689bd5fba1b7dff9abb1332e56f224fa vp90-2-17-show-existing-frame.webm-352x288-0026.i420
+e883aa425fa13c6d4eda2707d114d61d vp90-2-17-show-existing-frame.webm-352x288-0027.i420
+94d0bce08beb8a19c4ae12194a646935 vp90-2-17-show-existing-frame.webm-352x288-0028.i420
+cd317e97f5fd4be166308911c874f4e1 vp90-2-17-show-existing-frame.webm-352x288-0029.i420
+2fa245acd72d377cbb79c08faa02b330 vp90-2-17-show-existing-frame.webm-352x288-0030.i420
diff --git a/tests/tests/media/res/raw/vp90_2_19_skip.vp9 b/tests/tests/media/res/raw/vp90_2_19_skip.vp9
new file mode 100644
index 0000000..51c1173
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_19_skip.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_19_skip_01.vp9 b/tests/tests/media/res/raw/vp90_2_19_skip_01.vp9
new file mode 100644
index 0000000..b108df8
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_19_skip_01.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_19_skip_01_vp9_md5 b/tests/tests/media/res/raw/vp90_2_19_skip_01_vp9_md5
new file mode 100644
index 0000000..98fdce2
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_19_skip_01_vp9_md5
@@ -0,0 +1,60 @@
+6e350ec33af4ce08c18e884d7fd795aa 01.yuv
+abfb6e52a5a9d896b65e2c54e1f35f20 02.yuv
+e40e57536810c196f277f2d86fd7ef4d 03.yuv
+0b25dbe7b8218fcc67e700d332ef7ad7 04.yuv
+20f7737828b9a686a02a1b01cebb637f 05.yuv
+06d41fe61fbd8d96750882baac56954f 06.yuv
+9e6661eb3424978e105dfa393407c293 07.yuv
+2d9dd8d9625dc67cb342b9db51a9bf85 08.yuv
+d8d8671e8e921484acd0fd67c7046382 09.yuv
+f6513fee6d2de65d51239a689f45f1d6 10.yuv
+5a8c26cbe9cefc79481a1e24c36d1b07 11.yuv
+918c1080ca4f2d61049caaa963d58069 12.yuv
+9d028868e407a2a596ede1c7ec71997c 13.yuv
+0bf06f2b16acc2c9691953d0ba134e7b 14.yuv
+f340480004fd45b579bfa04487c94136 15.yuv
+a6ab04e5c72ab3612842e891644ef2f2 16.yuv
+cf5da560e869a73ac6dc37ff1812b14e 17.yuv
+4b9e24121a05b7f95e4c2ed5dc25aac9 18.yuv
+5e7c43edbf51d19cae31e348920e5848 19.yuv
+96e421b17ce7fea2428ea1fe8f7b500a 20.yuv
+0e2b1ef0e3d1cf4a2af7dd7cbb160f04 21.yuv
+bdcc399223320df2fab20bf365e4f3df 22.yuv
+26cf7f3d9c3e36c6d2f8af6e1c9f9b15 23.yuv
+d2ef6d0dfd7eca3d77b60f9c82191bf3 24.yuv
+76c07306ce9a627f37a6a5c8d66820a2 25.yuv
+7ee2428a7fbc3c88418167a8e52d438d 26.yuv
+68b267345e01d2fc72576f984f757a3c 27.yuv
+541bfb03ae1db20d693a0a92550e8df6 28.yuv
+e87cf619aefdb81e26a8ec70d6a12c2c 29.yuv
+621f1ed3976088b247d79504bdf03ca3 30.yuv
+2c6023819babc72f8ad936ec0f0ca85e 31.yuv
+9f5eae1311cfdd2c02ee63a978b8d6d2 32.yuv
+902112ada88fbd3fe006b713cf08f5aa 33.yuv
+ab5b451f7174520c57b096268272759c 34.yuv
+b686cba2b4c454de4e8e16f088db8354 35.yuv
+a68e934aa397819bb80bf4bd29134103 36.yuv
+6982347a3aa730c2f8a15c94bfb42b3d 37.yuv
+57c3f83402184dd80beb9f78f0c5cfc8 38.yuv
+adf66470bfdb88a860a17b74d0f5e99b 39.yuv
+e98d09d8d34d3c8d1cb6619794b1ed5b 40.yuv
+f839dce9aabf7db8b007d83766e05fa7 41.yuv
+3bad23fa7f6052582e319b9774e26030 42.yuv
+4220ba420816a3bc7030e1582942e74d 43.yuv
+f404671eaf5310565d0831684ff0f3ba 44.yuv
+8ba48a53a0178bcd596b880c8a96a61f 45.yuv
+7a8fbb7356e494a6cefe52c2b07e6dce 46.yuv
+fb7974be2a11fcfc71cc450727bf71ad 47.yuv
+5c9be4d4acac0b375be851cd3774a918 48.yuv
+83c84c97c9c5efd6dd56668cdbf18428 49.yuv
+626c9ab1e52f7d9c711e142b46e82a42 50.yuv
+8012dbe193dfa5d787445eaeecd9091b 51.yuv
+bc36350c60b92f77473158a9249d5383 52.yuv
+4e81e00620020b4c55f273796f023145 53.yuv
+f6161f425f0476821f8caa46360d87af 54.yuv
+509f724002e54baac7dd37b514c345da 55.yuv
+4ab2368ffa3854f433fd568883db0e55 56.yuv
+9934a8d1ae0bdd65aab070efa91ac778 57.yuv
+2f2c1b110107c1141053513f2596a599 58.yuv
+9da6ca6ef375a095f0c86cb8cb41db74 59.yuv
+125c735dc1fb523c8088e0815cd4cde1 60.yuv
diff --git a/tests/tests/media/res/raw/vp90_2_19_skip_02.vp9 b/tests/tests/media/res/raw/vp90_2_19_skip_02.vp9
new file mode 100644
index 0000000..770e311
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_19_skip_02.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_19_skip_02_vp9_md5 b/tests/tests/media/res/raw/vp90_2_19_skip_02_vp9_md5
new file mode 100644
index 0000000..80b3d65
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_19_skip_02_vp9_md5
@@ -0,0 +1,12 @@
+1ee94a4b059cd7380dabf71553aedf32 vp90-2-19-skip-02.webm-208x144-0001.i420
+d86167bfd6bca76c476c79361894a3f0 vp90-2-19-skip-02.webm-208x144-0002.i420
+421c9cd3b3474af8893fa44832b6fca7 vp90-2-19-skip-02.webm-208x144-0003.i420
+db0585dc48220105b8a3326222a66292 vp90-2-19-skip-02.webm-208x144-0004.i420
+15e5a53f39d7e350d356b0c4b2be4c82 vp90-2-19-skip-02.webm-208x144-0005.i420
+4d35f23245c90b5c0f013b4b2a085b2a vp90-2-19-skip-02.webm-208x144-0006.i420
+1e46a9945accfec93e345f50ebb520a0 vp90-2-19-skip-02.webm-208x144-0007.i420
+ea53419be2de85e9505aaed3a03a10e0 vp90-2-19-skip-02.webm-208x144-0008.i420
+14c17560d0690e929a40b6f2e46a458a vp90-2-19-skip-02.webm-208x144-0009.i420
+7c5eb58b81b57530391717a076114728 vp90-2-19-skip-02.webm-208x144-0010.i420
+57d4952e50ba519388ce7efca7ee505b vp90-2-19-skip-02.webm-208x144-0011.i420
+7bb3d99c86e135354ad437e5d80bf089 vp90-2-19-skip-02.webm-208x144-0012.i420
diff --git a/tests/tests/media/res/raw/vp90_2_19_skip_vp9_md5 b/tests/tests/media/res/raw/vp90_2_19_skip_vp9_md5
new file mode 100644
index 0000000..472b59a
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_19_skip_vp9_md5
@@ -0,0 +1,60 @@
+6e350ec33af4ce08c18e884d7fd795aa 01.yuv
+3f77603d7a5727db4017202310da1724 02.yuv
+983aae5424ab39af07adcf78d43a23ba 03.yuv
+a0cdeaa0eb6eda3750d268434391a7ab 04.yuv
+64325c99444e566989c6eeaa8ffeee32 05.yuv
+8320f52b7fcd0565465941c50a01b801 06.yuv
+d6bb76bf65b70b86bda891fe807fcd26 07.yuv
+c44b46422d2be0b831d27fab61a0d374 08.yuv
+414ce4220e0aef53cb5966990ae00bb6 09.yuv
+2bf82867941dc68b0d60cede97f2d4d7 10.yuv
+593c676743ffaf1a5be85d74529dbb3f 11.yuv
+ccac5f0992545c35d227a021cb91b6f6 12.yuv
+bbb637aaed37f7cc6068802531152b77 13.yuv
+41e2d71a3ff3ed9d225348eb6be72853 14.yuv
+7ed3f76508059c281f75e2043d7d6677 15.yuv
+ed330eefed85685bed2bc1c5dc409d24 16.yuv
+61c4c435237e06623b6994f43b469833 17.yuv
+1e27f96fe683a654b228360f7a1beee1 18.yuv
+090e025ec148ec53f802cdb8ed0bfd77 19.yuv
+20d0caa6d4ab9db05869fd0532a2265f 20.yuv
+e11d108db8822b07a6fe8216b34fa259 21.yuv
+bdb3421bffee6eeafa00255ffcdcf1fe 22.yuv
+cb090c2f2d28679d1e2eb2c04150d751 23.yuv
+7f8eec67552bbac654f9a374d7a985ca 24.yuv
+5c039c621c9c20947f75b98b7e579ce8 25.yuv
+464be7de183b98138d8e9fb61ef613ec 26.yuv
+b887a102c6399d33307ac434d0ab3fd4 27.yuv
+e8fa163067c77e27b9089b4a48b444c0 28.yuv
+d92e13465475df261f9469171ac962cc 29.yuv
+8e6a8ba99387bc4cf7aee0aab6d132f4 30.yuv
+4625d7b6b23ddc840941a4f4d7739daa 31.yuv
+3b8533887142da49fdb24569dd34c2ac 32.yuv
+9ff94cefac26936cbf284e7482b2433d 33.yuv
+68b2fec46494c24501e48927fe9636e5 34.yuv
+7d76bfa0ebb09f27482288a0d61cd0e8 35.yuv
+27b630a10fc1790884e16bbb0fef37ee 36.yuv
+322de7f87166725fdd48373b28156593 37.yuv
+d73c7bd37eccd47df4a5b27cecbb8cea 38.yuv
+c3679a0317d1efc2b76e3dd97baa4070 39.yuv
+e3f9523bd41a280b922cdcf188911de2 40.yuv
+b57f28d944f4f39ab9c97a5ae8e3beda 41.yuv
+520a2b794f4384cf4c38f8d4c5b9c7bb 42.yuv
+bc215f65a73183da31b4bd896db178b4 43.yuv
+ab3c86d15728db474a45c544c2103745 44.yuv
+1287678d28e400a47a4f21b8854339d7 45.yuv
+be3f1eb3f48706e4e37aff83f0434fab 46.yuv
+dbc71f50dd620e058da88c414041ca57 47.yuv
+3d68bf9ae1e6065bf70eee87fbb9a2ce 48.yuv
+c901fac66677a4be1b624d6995af1ea3 49.yuv
+0756c5dd31c691df91a535910d8756e0 50.yuv
+b9c30e56f000a71148ababdf7c7bbae3 51.yuv
+2dc2917b1c0e498dd8e83abcdc48e3ca 52.yuv
+057ce1fe6eb8800ec8ec47720e70ed74 53.yuv
+1c25a6c9e182fa7fbef473ad9be476ea 54.yuv
+3ae770d42403b5069d0fa97e11cec3b0 55.yuv
+e5c19d46df1c711a650229867073246c 56.yuv
+cfc5f6cbb0a319d8bfb3feffddbb8f48 57.yuv
+86e42a5e03bc537505589f7fa39bff2b 58.yuv
+cdf32bda09d594763068d6fa0ff67b98 59.yuv
+0d6be7f95a7e3941950f14e20be11020 60.yuv
diff --git a/tests/tests/media/res/raw/vp90_2_20_big_superframe_01.vp9 b/tests/tests/media/res/raw/vp90_2_20_big_superframe_01.vp9
new file mode 100644
index 0000000..6a45085
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_20_big_superframe_01.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_20_big_superframe_01_vp9_md5 b/tests/tests/media/res/raw/vp90_2_20_big_superframe_01_vp9_md5
new file mode 100644
index 0000000..4fe4dcc
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_20_big_superframe_01_vp9_md5
@@ -0,0 +1,13 @@
+b5d461894f957709576d15f6dce3d69e vp90-2-20-big_superframe-01.webm-352x288-0001.i420
+b14448e30621b5d2d0a18c2e12ef0d95 vp90-2-20-big_superframe-01.webm-352x288-0002.i420
+4584cf6ffe6ca91fa3926cb88b6dab2d vp90-2-20-big_superframe-01.webm-352x288-0003.i420
+ff83dd3c0dfdd8740523f560a9d7abfe vp90-2-20-big_superframe-01.webm-352x288-0004.i420
+a2a1dc9b91b0e4fd6ecc8fa53a156ed9 vp90-2-20-big_superframe-01.webm-352x288-0005.i420
+13f953ae1cfa25c5996d77fc88070452 vp90-2-20-big_superframe-01.webm-352x288-0006.i420
+81dd4bdf32f7998fdc221a4612e022ce vp90-2-20-big_superframe-01.webm-352x288-0007.i420
+518bbee70ad6488ea3d69e0e34a133a4 vp90-2-20-big_superframe-01.webm-352x288-0008.i420
+acae8f0ab72c6daa3a280fa41fbbb22e vp90-2-20-big_superframe-01.webm-352x288-0009.i420
+fbfb93207c09242ee49637e740f3f870 vp90-2-20-big_superframe-01.webm-352x288-0010.i420
+20b072932f592e67d92cb67b224620b1 vp90-2-20-big_superframe-01.webm-352x288-0011.i420
+ddab6752606406c5b25d4e3b3208e381 vp90-2-20-big_superframe-01.webm-352x288-0012.i420
+6525d6826964e8b54fa982a300088ce3 vp90-2-20-big_superframe-01.webm-352x288-0013.i420
diff --git a/tests/tests/media/res/raw/vp90_2_20_big_superframe_02.vp9 b/tests/tests/media/res/raw/vp90_2_20_big_superframe_02.vp9
new file mode 100644
index 0000000..73137af
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_20_big_superframe_02.vp9
Binary files differ
diff --git a/tests/tests/media/res/raw/vp90_2_20_big_superframe_02_vp9_md5 b/tests/tests/media/res/raw/vp90_2_20_big_superframe_02_vp9_md5
new file mode 100644
index 0000000..8ca8576
--- /dev/null
+++ b/tests/tests/media/res/raw/vp90_2_20_big_superframe_02_vp9_md5
@@ -0,0 +1,18 @@
+b5d461894f957709576d15f6dce3d69e vp90-2-20-big_superframe-02.webm-352x288-0001.i420
+54e45dfe575d9843c198270f62154c09 vp90-2-20-big_superframe-02.webm-352x288-0002.i420
+87749847c291a46c0ae0ca5d5002cb5f vp90-2-20-big_superframe-02.webm-352x288-0003.i420
+04d7f341b081b35fd14ddfd777607fb1 vp90-2-20-big_superframe-02.webm-352x288-0004.i420
+81c73e1129b94936d53d33f8c66588e9 vp90-2-20-big_superframe-02.webm-352x288-0005.i420
+678b99102426df6a69184acc142c0c6a vp90-2-20-big_superframe-02.webm-352x288-0006.i420
+a91f8d509a3e853e71b78b7ebe162428 vp90-2-20-big_superframe-02.webm-352x288-0007.i420
+9981ac3b4b78627c4474222823a9b288 vp90-2-20-big_superframe-02.webm-352x288-0008.i420
+400adf7ab42c47954db9086b5fcb2ef8 vp90-2-20-big_superframe-02.webm-352x288-0009.i420
+fc917ebef7115a04f0bf4e06e1e1a2a9 vp90-2-20-big_superframe-02.webm-352x288-0010.i420
+72271e7946c9dd99a947df787caaadfe vp90-2-20-big_superframe-02.webm-352x288-0011.i420
+acb81daaaa35d651a87a9f8e87f813b3 vp90-2-20-big_superframe-02.webm-352x288-0012.i420
+e6ffc22ab1a918e3f1af384f0dd22ff9 vp90-2-20-big_superframe-02.webm-352x288-0013.i420
+3ecbc78c737312948d8c172d1c2d2383 vp90-2-20-big_superframe-02.webm-352x288-0014.i420
+320edb7fddfe8c98e616702d11f8f456 vp90-2-20-big_superframe-02.webm-352x288-0015.i420
+cf8363cebf34bdefd2c8e2178de5ef23 vp90-2-20-big_superframe-02.webm-352x288-0016.i420
+d15c8f1bc21ad09ad881a59b5f2b8167 vp90-2-20-big_superframe-02.webm-352x288-0017.i420
+c5c9f8b1826fac50655ed1454ae78279 vp90-2-20-big_superframe-02.webm-352x288-0018.i420
diff --git a/tests/tests/media/res/raw/vp9_test_vectors b/tests/tests/media/res/raw/vp9_test_vectors
new file mode 100644
index 0000000..a9dc4f3
--- /dev/null
+++ b/tests/tests/media/res/raw/vp9_test_vectors
@@ -0,0 +1,235 @@
+vp90_2_00_quantizer_00
+vp90_2_00_quantizer_01
+vp90_2_00_quantizer_02
+vp90_2_00_quantizer_03
+vp90_2_00_quantizer_04
+vp90_2_00_quantizer_05
+vp90_2_00_quantizer_06
+vp90_2_00_quantizer_07
+vp90_2_00_quantizer_08
+vp90_2_00_quantizer_09
+vp90_2_00_quantizer_10
+vp90_2_00_quantizer_11
+vp90_2_00_quantizer_12
+vp90_2_00_quantizer_13
+vp90_2_00_quantizer_14
+vp90_2_00_quantizer_15
+vp90_2_00_quantizer_16
+vp90_2_00_quantizer_17
+vp90_2_00_quantizer_18
+vp90_2_00_quantizer_19
+vp90_2_00_quantizer_20
+vp90_2_00_quantizer_21
+vp90_2_00_quantizer_22
+vp90_2_00_quantizer_23
+vp90_2_00_quantizer_24
+vp90_2_00_quantizer_25
+vp90_2_00_quantizer_26
+vp90_2_00_quantizer_27
+vp90_2_00_quantizer_28
+vp90_2_00_quantizer_29
+vp90_2_00_quantizer_30
+vp90_2_00_quantizer_31
+vp90_2_00_quantizer_32
+vp90_2_00_quantizer_33
+vp90_2_00_quantizer_34
+vp90_2_00_quantizer_35
+vp90_2_00_quantizer_36
+vp90_2_00_quantizer_37
+vp90_2_00_quantizer_38
+vp90_2_00_quantizer_39
+vp90_2_00_quantizer_40
+vp90_2_00_quantizer_41
+vp90_2_00_quantizer_42
+vp90_2_00_quantizer_43
+vp90_2_00_quantizer_44
+vp90_2_00_quantizer_45
+vp90_2_00_quantizer_46
+vp90_2_00_quantizer_47
+vp90_2_00_quantizer_48
+vp90_2_00_quantizer_49
+vp90_2_00_quantizer_50
+vp90_2_00_quantizer_51
+vp90_2_00_quantizer_52
+vp90_2_00_quantizer_53
+vp90_2_00_quantizer_54
+vp90_2_00_quantizer_55
+vp90_2_00_quantizer_56
+vp90_2_00_quantizer_57
+vp90_2_00_quantizer_58
+vp90_2_00_quantizer_59
+vp90_2_00_quantizer_60
+vp90_2_00_quantizer_61
+vp90_2_00_quantizer_62
+vp90_2_00_quantizer_63
+vp90_2_01_sharpness_1
+vp90_2_01_sharpness_2
+vp90_2_01_sharpness_3
+vp90_2_01_sharpness_4
+vp90_2_01_sharpness_5
+vp90_2_01_sharpness_6
+vp90_2_01_sharpness_7
+vp90_2_02_size_08x08
+vp90_2_02_size_08x10
+vp90_2_02_size_08x16
+vp90_2_02_size_08x18
+vp90_2_02_size_08x32
+vp90_2_02_size_08x34
+vp90_2_02_size_08x64
+vp90_2_02_size_08x66
+vp90_2_02_size_10x08
+vp90_2_02_size_10x10
+vp90_2_02_size_10x16
+vp90_2_02_size_10x18
+vp90_2_02_size_10x32
+vp90_2_02_size_10x34
+vp90_2_02_size_10x64
+vp90_2_02_size_10x66
+vp90_2_02_size_16x08
+vp90_2_02_size_16x10
+vp90_2_02_size_16x16
+vp90_2_02_size_16x18
+vp90_2_02_size_16x32
+vp90_2_02_size_16x34
+vp90_2_02_size_16x64
+vp90_2_02_size_16x66
+vp90_2_02_size_18x08
+vp90_2_02_size_18x10
+vp90_2_02_size_18x16
+vp90_2_02_size_18x18
+vp90_2_02_size_18x32
+vp90_2_02_size_18x34
+vp90_2_02_size_18x64
+vp90_2_02_size_18x66
+vp90_2_02_size_32x08
+vp90_2_02_size_32x10
+vp90_2_02_size_32x16
+vp90_2_02_size_32x18
+vp90_2_02_size_32x32
+vp90_2_02_size_32x34
+vp90_2_02_size_32x64
+vp90_2_02_size_32x66
+vp90_2_02_size_34x08
+vp90_2_02_size_34x10
+vp90_2_02_size_34x16
+vp90_2_02_size_34x18
+vp90_2_02_size_34x32
+vp90_2_02_size_34x34
+vp90_2_02_size_34x64
+vp90_2_02_size_34x66
+vp90_2_02_size_64x08
+vp90_2_02_size_64x10
+vp90_2_02_size_64x16
+vp90_2_02_size_64x18
+vp90_2_02_size_64x32
+vp90_2_02_size_64x34
+vp90_2_02_size_64x64
+vp90_2_02_size_64x66
+vp90_2_02_size_66x08
+vp90_2_02_size_66x10
+vp90_2_02_size_66x16
+vp90_2_02_size_66x18
+vp90_2_02_size_66x32
+vp90_2_02_size_66x34
+vp90_2_02_size_66x64
+vp90_2_02_size_66x66
+vp90_2_02_size_130x132
+vp90_2_02_size_132x130
+vp90_2_02_size_132x132
+vp90_2_02_size_178x180
+vp90_2_02_size_180x178
+vp90_2_02_size_180x180
+vp90_2_03_size_196x196
+vp90_2_03_size_196x198
+vp90_2_03_size_196x200
+vp90_2_03_size_196x202
+vp90_2_03_size_196x208
+vp90_2_03_size_196x210
+vp90_2_03_size_196x224
+vp90_2_03_size_196x226
+vp90_2_03_size_198x196
+vp90_2_03_size_198x198
+vp90_2_03_size_198x200
+vp90_2_03_size_198x202
+vp90_2_03_size_198x208
+vp90_2_03_size_198x210
+vp90_2_03_size_198x224
+vp90_2_03_size_198x226
+vp90_2_03_size_200x196
+vp90_2_03_size_200x198
+vp90_2_03_size_200x200
+vp90_2_03_size_200x202
+vp90_2_03_size_200x208
+vp90_2_03_size_200x210
+vp90_2_03_size_200x224
+vp90_2_03_size_200x226
+vp90_2_03_size_202x196
+vp90_2_03_size_202x198
+vp90_2_03_size_202x200
+vp90_2_03_size_202x202
+vp90_2_03_size_202x208
+vp90_2_03_size_202x210
+vp90_2_03_size_202x224
+vp90_2_03_size_202x226
+vp90_2_03_size_208x196
+vp90_2_03_size_208x198
+vp90_2_03_size_208x200
+vp90_2_03_size_208x202
+vp90_2_03_size_208x208
+vp90_2_03_size_208x210
+vp90_2_03_size_208x224
+vp90_2_03_size_208x226
+vp90_2_03_size_210x196
+vp90_2_03_size_210x198
+vp90_2_03_size_210x200
+vp90_2_03_size_210x202
+vp90_2_03_size_210x208
+vp90_2_03_size_210x210
+vp90_2_03_size_210x224
+vp90_2_03_size_210x226
+vp90_2_03_size_224x196
+vp90_2_03_size_224x198
+vp90_2_03_size_224x200
+vp90_2_03_size_224x202
+vp90_2_03_size_224x208
+vp90_2_03_size_224x210
+vp90_2_03_size_224x224
+vp90_2_03_size_224x226
+vp90_2_03_size_226x196
+vp90_2_03_size_226x198
+vp90_2_03_size_226x200
+vp90_2_03_size_226x202
+vp90_2_03_size_226x208
+vp90_2_03_size_226x210
+vp90_2_03_size_226x224
+vp90_2_03_size_226x226
+vp90_2_02_size_lf_1920x1080
+vp90_2_03_deltaq
+vp90_2_06_bilinear
+vp90_2_07_frame_parallel_1
+vp90_2_07_frame_parallel
+vp90_2_08_tile_1x2_frame_parallel
+vp90_2_08_tile_1x2
+vp90_2_08_tile_1x4_frame_parallel
+vp90_2_08_tile_1x4
+vp90_2_08_tile_1x8_frame_parallel
+vp90_2_08_tile_1x8
+vp90_2_08_tile_4x1
+vp90_2_08_tile_4x4
+vp90_2_09_aq2
+vp90_2_09_lf_deltas
+vp90_2_09_subpixel_00
+vp90_2_10_show_existing_frame2
+vp90_2_10_show_existing_frame
+vp90_2_12_droppable_1
+vp90_2_12_droppable_2
+vp90_2_12_droppable_3
+vp90_2_15_segkey_adpq
+vp90_2_15_segkey
+vp90_2_16_intra_only
+vp90_2_17_show_existing_frame
+vp90_2_19_skip_01
+vp90_2_19_skip_02
+vp90_2_19_skip
+vp90_2_20_big_superframe_01
+vp90_2_20_big_superframe_02
diff --git a/tests/tests/media/src/android/media/cts/CodecUtils.java b/tests/tests/media/src/android/media/cts/CodecUtils.java
index b7ebb88..dd8efdb 100644
--- a/tests/tests/media/src/android/media/cts/CodecUtils.java
+++ b/tests/tests/media/src/android/media/cts/CodecUtils.java
@@ -16,12 +16,18 @@
package android.media.cts;
+import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.media.cts.CodecImage;
import android.media.Image;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
import android.util.Log;
import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.util.ArrayList;
public class CodecUtils {
private static final String TAG = "CodecUtils";
@@ -140,5 +146,100 @@
}
public native static float[] Raw2YUVStats(long[] rawStats);
+
+ public static String[] getDecoderNames(String mime, boolean isGoog) {
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ ArrayList<String> result = new ArrayList<String>();
+ for (MediaCodecInfo info : mcl.getCodecInfos()) {
+ CodecCapabilities caps = null;
+ try {
+ caps = info.getCapabilitiesForType(mime);
+ } catch (IllegalArgumentException e) { // mime is not supported
+ continue;
+ }
+ result.add(info.getName());
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ public static String getImageMD5Checksum(Image image) throws Exception {
+ int format = image.getFormat();
+ if (ImageFormat.YUV_420_888 != format) {
+ Log.w(TAG, "unsupported image format");
+ return "";
+ }
+
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+
+ Image.Plane[] planes = image.getPlanes();
+ for (int i = 0; i < planes.length; ++i) {
+ ByteBuffer buf = planes[i].getBuffer();
+
+ int width, height, rowStride, pixelStride, x, y;
+ rowStride = planes[i].getRowStride();
+ pixelStride = planes[i].getPixelStride();
+ if (i == 0) {
+ width = imageWidth;
+ height = imageHeight;
+ } else {
+ width = imageWidth / 2;
+ height = imageHeight /2;
+ }
+ // local contiguous pixel buffer
+ byte[] bb = new byte[width * height];
+ if (buf.hasArray()) {
+ byte b[] = buf.array();
+ int offs = buf.arrayOffset();
+ if (pixelStride == 1) {
+ for (y = 0; y < height; ++y) {
+ System.arraycopy(bb, y * width, b, y * rowStride + offs, width);
+ }
+ } else {
+ // do it pixel-by-pixel
+ for (y = 0; y < height; ++y) {
+ int lineOffset = offs + y * rowStride;
+ for (x = 0; x < width; ++x) {
+ bb[y * width + x] = b[lineOffset + x * pixelStride];
+ }
+ }
+ }
+ } else { // almost always ends up here due to direct buffers
+ int pos = buf.position();
+ if (pixelStride == 1) {
+ for (y = 0; y < height; ++y) {
+ buf.position(pos + y * rowStride);
+ buf.get(bb, y * width, width);
+ }
+ } else {
+ // local line buffer
+ byte[] lb = new byte[rowStride];
+ // do it pixel-by-pixel
+ for (y = 0; y < height; ++y) {
+ buf.position(pos + y * rowStride);
+ // we're only guaranteed to have pixelStride * (width - 1) + 1 bytes
+ buf.get(lb, 0, pixelStride * (width - 1) + 1);
+ for (x = 0; x < width; ++x) {
+ bb[y * width + x] = lb[x * pixelStride];
+ }
+ }
+ }
+ buf.position(pos);
+ }
+ md.update(bb, 0, width * height);
+ }
+
+ return convertByteArrayToHEXString(md.digest());
+ }
+
+ private static String convertByteArrayToHEXString(byte[] ba) throws Exception {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < ba.length; i++) {
+ result.append(Integer.toString((ba[i] & 0xff) + 0x100, 16).substring(1));
+ }
+ return result.toString();
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java b/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
new file mode 100644
index 0000000..7a49fd0
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecoderConformanceTest.java
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.cts.util.DeviceReportLog;
+import android.cts.util.MediaUtils;
+import android.media.cts.CodecUtils;
+import android.media.Image;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.util.Range;
+
+import com.android.cts.util.ResultType;
+import com.android.cts.util.ResultUnit;
+import com.android.compatibility.common.util.Stat;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Conformance test for decoders on the device.
+ *
+ * This test will decode test vectors and calculate every decoded frame's md5
+ * checksum to see if it matches with the correct md5 value read from a
+ * reference file associated with the test vector. Test vector md5 sums are
+ * based on the YUV 420 plannar format.
+ */
+public class DecoderConformanceTest extends MediaPlayerTestBase {
+ private static enum Status {
+ FAIL,
+ PASS,
+ SKIP;
+ }
+
+ private static final String TAG = "DecoderConformanceTest";
+ private Resources mResources;
+ private DeviceReportLog mReportLog;
+ private MediaCodec mDecoder;
+ private MediaExtractor mExtractor;
+
+ private static final Map<String, String> MIMETYPE_TO_TAG = new HashMap <String, String>() {{
+ put(MediaFormat.MIMETYPE_VIDEO_VP9, "vp9");
+ }};
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ mReportLog = new DeviceReportLog();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mReportLog.deliverReportToHost(getInstrumentation());
+ super.tearDown();
+ }
+
+
+ private List<String> readResourceLines(String fileName) throws Exception {
+ int resId = mResources.getIdentifier(fileName, "raw", mContext.getPackageName());
+ InputStream is = mContext.getResources().openRawResource(resId);
+ BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+
+ // Read the file line by line.
+ List<String> lines = new ArrayList<String>();
+ String str;
+ while ((str = in.readLine()) != null) {
+ int k = str.indexOf(' ');
+ String line = k >= 0 ? str.substring(0, k) : str;
+ lines.add(line);
+ }
+
+ is.close();
+ return lines;
+ }
+
+ private List<String> readCodecTestVectors(String mime) throws Exception {
+ String tag = MIMETYPE_TO_TAG.get(mime);
+ String testVectorFileName = tag + "_test_vectors";
+ return readResourceLines(testVectorFileName);
+ }
+
+ private List<String> readVectorMD5Sums(String mime, String vectorName) throws Exception {
+ String tag = MIMETYPE_TO_TAG.get(mime);
+ String md5FileName = vectorName + "_" + tag + "_md5";
+ return readResourceLines(md5FileName);
+ }
+
+ private void releaseMediacodec() {
+ try {
+ mDecoder.stop();
+ } catch (Exception e) {
+ Log.e(TAG, "Mediacodec stop exception");
+ }
+
+ try {
+ mDecoder.release();
+ mExtractor.release();
+ } catch (Exception e) {
+ Log.e(TAG, "Mediacodec release exception");
+ }
+
+ mDecoder = null;
+ mExtractor = null;
+ }
+
+ private Status decodeTestVector(String mime, String decoderName, String vectorName) throws Exception {
+ int resId = mResources.getIdentifier(vectorName, "raw", mContext.getPackageName());
+ AssetFileDescriptor testFd = mResources.openRawResourceFd(resId);
+ mExtractor = new MediaExtractor();
+ mExtractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
+ testFd.getLength());
+ mExtractor.selectTrack(0);
+ int trackIndex = mExtractor.getSampleTrackIndex();
+ MediaFormat format = mExtractor.getTrackFormat(trackIndex);
+ mDecoder = MediaCodec.createByCodecName(decoderName);
+
+ MediaCodecInfo codecInfo = mDecoder.getCodecInfo();
+ MediaCodecInfo.CodecCapabilities caps = codecInfo.getCapabilitiesForType(mime);
+ if (!caps.isFormatSupported(format)) {
+ return Status.SKIP;
+ }
+
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ int decodeFrameCount = 0;
+ boolean sawInputEOS = false;
+ boolean sawOutputEOS = false;
+ final long kTimeOutUs = 5000; // 5ms timeout
+ List<String> frameMD5Sums;
+
+ try {
+ frameMD5Sums = readVectorMD5Sums(mime, vectorName);
+ } catch(Exception e) {
+ Log.e(TAG, "Fail to read " + vectorName + "md5sum file");
+ return Status.FAIL;
+ }
+
+ int expectFrameCount = frameMD5Sums.size();
+ mDecoder.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
+ mDecoder.start();
+
+ while (!sawOutputEOS) {
+ // handle input
+ if (!sawInputEOS) {
+ int inputIndex = mDecoder.dequeueInputBuffer(kTimeOutUs);
+ if (inputIndex >= 0) {
+ ByteBuffer buffer = mDecoder.getInputBuffer(inputIndex);
+ int sampleSize = mExtractor.readSampleData(buffer, 0);
+ if (sampleSize < 0) {
+ mDecoder.queueInputBuffer(inputIndex, 0, 0, 0,
+ MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ sawInputEOS = true;
+ } else {
+ mDecoder.queueInputBuffer(inputIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
+ mExtractor.advance();
+ }
+ }
+ }
+
+ // handle output
+ int outputBufIndex = mDecoder.dequeueOutputBuffer(info, kTimeOutUs);
+ if (outputBufIndex >= 0) {
+ if (info.size > 0) { // Disregard 0-sized buffers at the end.
+ MediaFormat bufferFormat = mDecoder.getOutputFormat(outputBufIndex);
+ int width = bufferFormat.getInteger(MediaFormat.KEY_WIDTH);
+ int height = bufferFormat.getInteger(MediaFormat.KEY_HEIGHT);
+ int colorFmt = bufferFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+
+ String md5CheckSum = "";
+ try {
+ Image image = mDecoder.getOutputImage(outputBufIndex);
+ md5CheckSum = CodecUtils.getImageMD5Checksum(image);
+ } catch (Exception e) {
+ Log.e(TAG, "getOutputImage md5CheckSum failed", e);
+ return Status.FAIL;
+ }
+
+ if (!md5CheckSum.equals(frameMD5Sums.get(decodeFrameCount))) {
+ Log.d(TAG, "Frame " + decodeFrameCount + " md5sum mismatch");
+ return Status.FAIL;
+ }
+
+ decodeFrameCount++;
+ }
+ mDecoder.releaseOutputBuffer(outputBufIndex, false /* render */);
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ sawOutputEOS = true;
+ }
+ } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat decOutputFormat = mDecoder.getOutputFormat();
+ int width = decOutputFormat.getInteger(MediaFormat.KEY_WIDTH);
+ int height = decOutputFormat.getInteger(MediaFormat.KEY_HEIGHT);
+ Log.d(TAG, "output format " + decOutputFormat);
+ } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ Log.i(TAG, "Skip handling MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED");
+ } else {
+ assertEquals(
+ "decoder.dequeueOutputBuffer() unrecognized return index: " + outputBufIndex,
+ MediaCodec.INFO_TRY_AGAIN_LATER, outputBufIndex);
+ }
+ }
+
+ if (decodeFrameCount != expectFrameCount) {
+ Log.d(TAG, vectorName + " decode frame count not match");
+ return Status.FAIL;
+ }
+
+ mDecoder.stop();
+ mDecoder.release();
+ mExtractor.release();
+ return Status.PASS;
+ }
+
+ void decodeTestVectors(String mime, boolean isGoog) throws Exception {
+ String[] decoderNames = CodecUtils.getDecoderNames(mime, isGoog);
+ for (String decoderName: decoderNames) {
+ List<String> testVectors = readCodecTestVectors(mime);
+ for (String vectorName: testVectors) {
+ boolean pass = false;
+ Log.d(TAG, "Decode vector " + vectorName + " with " + decoderName);
+ try {
+ Status stat = decodeTestVector(mime, decoderName, vectorName);
+ if (stat == Status.PASS) {
+ pass = true;
+ } else if (stat == Status.SKIP) {
+ continue;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Decode " + vectorName + " fail");
+ }
+
+ if (pass) {
+ mReportLog.printValue(vectorName, 1, ResultType.NEUTRAL, ResultUnit.NONE);
+ } else {
+ mReportLog.printValue(vectorName, 0, ResultType.NEUTRAL, ResultUnit.NONE);
+ // Release mediacodec in failure or exception casees.
+ releaseMediacodec();
+ }
+ }
+ mReportLog.printSummary(decoderName, 0, ResultType.NEUTRAL, ResultUnit.NONE);
+ }
+ }
+
+ /**
+ * Test VP9 decoders from vendor.
+ */
+ public void testVP9Other() throws Exception {
+ decodeTestVectors(MediaFormat.MIMETYPE_VIDEO_VP9, false /* isGoog */);
+ }
+
+ /**
+ * Test Google's VP9 decoder from libvpx.
+ */
+ public void testVP9Goog() throws Exception {
+ decodeTestVectors(MediaFormat.MIMETYPE_VIDEO_VP9, true /* isGoog */);
+ }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/IvfWriter.java b/tests/tests/media/src/android/media/cts/IvfWriter.java
index 075f73c..36fb679 100644
--- a/tests/tests/media/src/android/media/cts/IvfWriter.java
+++ b/tests/tests/media/src/android/media/cts/IvfWriter.java
@@ -16,6 +16,8 @@
package android.media.cts;
+import android.media.MediaFormat;
+
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -34,6 +36,7 @@
private int mScale;
private int mRate;
private int mFrameCount;
+ private String mMimeType;
/**
* Initializes the IVF file writer.
@@ -43,15 +46,17 @@
* with this timebase value.
*
* @param filename name of the IVF file
+ * @param mimeType mime type of the codec
* @param width frame width
* @param height frame height
* @param scale timebase scale (or numerator of the timebase fraction)
* @param rate timebase rate (or denominator of the timebase fraction)
*/
- public IvfWriter(String filename,
- int width, int height,
- int scale, int rate) throws IOException {
+ public IvfWriter(
+ String filename, String mimeType, int width, int height, int scale,
+ int rate) throws IOException {
mOutputFile = new RandomAccessFile(filename, "rw");
+ mMimeType = mimeType;
mWidth = width;
mHeight = height;
mScale = scale;
@@ -67,11 +72,12 @@
* Microsecond timebase is default for OMX thus stagefright.
*
* @param filename name of the IVF file
+ * @param mimeType mime type of the codec
* @param width frame width
* @param height frame height
*/
- public IvfWriter(String filename, int width, int height) throws IOException {
- this(filename, width, height, 1, 1000000);
+ public IvfWriter(String filename, String mimeType, int width, int height) throws IOException {
+ this(filename, mimeType, width, height, 1, 1000000);
}
/**
@@ -80,7 +86,7 @@
public void close() throws IOException{
// Write header now
mOutputFile.seek(0);
- mOutputFile.write(makeIvfHeader(mFrameCount, mWidth, mHeight, mScale, mRate));
+ mOutputFile.write(makeIvfHeader(mFrameCount, mWidth, mHeight, mScale, mRate, mMimeType));
mOutputFile.close();
}
@@ -107,7 +113,8 @@
* @param scale timebase scale (or numerator of the timebase fraction)
* @param rate timebase rate (or denominator of the timebase fraction)
*/
- private static byte[] makeIvfHeader(int frameCount, int width, int height, int scale, int rate){
+ private static byte[] makeIvfHeader(
+ int frameCount, int width, int height, int scale, int rate, String mimeType) {
byte[] ivfHeader = new byte[32];
ivfHeader[0] = 'D';
ivfHeader[1] = 'K';
@@ -117,7 +124,7 @@
lay16Bits(ivfHeader, 6, 32); // header size
ivfHeader[8] = 'V'; // fourcc
ivfHeader[9] = 'P';
- ivfHeader[10] = '8';
+ ivfHeader[10] = (byte) (MediaFormat.MIMETYPE_VIDEO_VP8.equals(mimeType) ? '8' : '9');
ivfHeader[11] = '0';
lay16Bits(ivfHeader, 12, width);
lay16Bits(ivfHeader, 14, height);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 5b2936b..b579c6d 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -52,12 +52,8 @@
private static final int TIMEOUT_US = 1000000; // 1 sec
private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
- private final MediaCodecList mRegularCodecs =
- new MediaCodecList(MediaCodecList.REGULAR_CODECS);
private final MediaCodecList mAllCodecs =
new MediaCodecList(MediaCodecList.ALL_CODECS);
- private final MediaCodecInfo[] mRegularInfos =
- mRegularCodecs.getCodecInfos();
private final MediaCodecInfo[] mAllInfos =
mAllCodecs.getCodecInfos();
@@ -391,7 +387,7 @@
// check if there is an adaptive decoder for each
for (String mime : supportedFormats) {
skipped = false;
- // implicit assumption that QVGA video is always valid.
+ // implicit assumption that QCIF video is always valid.
MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
format.setFeatureEnabled(CodecCapabilities.FEATURE_AdaptivePlayback, true);
String codec = mAllCodecs.findDecoderForFormat(format);
@@ -501,7 +497,7 @@
MediaFormat format = null;
try {
codec = MediaCodec.createByCodecName(info.getName());
- // implicit assumption that QVGA video is always valid.
+ // implicit assumption that QCIF video is always valid.
format = createReasonableVideoFormat(caps, mime, isEncoder, 176, 144);
format.setInteger(
MediaFormat.KEY_COLOR_FORMAT,
diff --git a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java b/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
deleted file mode 100644
index 0395ec7..0000000
--- a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
+++ /dev/null
@@ -1,2000 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.cts;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.media.MediaCodec;
-import android.media.MediaCodec.CodecException;
-import android.media.MediaCodecInfo.CodecCapabilities;
-import android.media.MediaCodecList;
-import android.media.MediaCodecInfo;
-import android.media.MediaFormat;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Looper;
-import android.os.Handler;
-import android.test.AndroidTestCase;
-import android.util.Log;
-import android.media.cts.R;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.util.Locale;
-import java.util.ArrayList;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * Verification test for vp8 encoder and decoder.
- *
- * A raw yv12 stream is encoded at various settings and written to an IVF
- * file. Encoded stream bitrate and key frame interval are checked against target values.
- * The stream is later decoded by vp8 decoder to verify frames are decodable and to
- * calculate PSNR values for various bitrates.
- */
-public class Vp8CodecTestBase extends AndroidTestCase {
-
- protected static final String TAG = "VP8CodecTestBase";
- protected static final String VP8_MIME = MediaFormat.MIMETYPE_VIDEO_VP8;
- private static final String GOOGLE_CODEC_PREFIX = "omx.google.";
- protected static final String SDCARD_DIR =
- Environment.getExternalStorageDirectory().getAbsolutePath();
-
- // Default timeout for MediaCodec buffer dequeue - 200 ms.
- protected static final long DEFAULT_DEQUEUE_TIMEOUT_US = 200000;
- // Default timeout for MediaEncoderAsync - 30 sec.
- protected static final long DEFAULT_ENCODE_TIMEOUT_MS = 30000;
- // Default sync frame interval in frames (zero means allow the encoder to auto-select
- // key frame interval).
- private static final int SYNC_FRAME_INTERVAL = 0;
- // Video bitrate type - should be set to OMX_Video_ControlRateConstant from OMX_Video.h
- protected static final int VIDEO_ControlRateVariable = 1;
- protected static final int VIDEO_ControlRateConstant = 2;
- // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
- // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
- private static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
- // Allowable color formats supported by codec - in order of preference.
- private static final int[] mSupportedColorList = {
- CodecCapabilities.COLOR_FormatYUV420Planar,
- CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
- CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
- COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
- };
- // Scaled image cache list - contains scale factors, for which up-scaled frames
- // were calculated and were written to yuv file.
- ArrayList<Integer> mScaledImages = new ArrayList<Integer>();
-
- private Resources mResources;
-
- @Override
- public void setContext(Context context) {
- super.setContext(context);
- mResources = mContext.getResources();
- }
-
- /**
- * VP8 codec properties generated by getVp8CodecProperties() function.
- */
- private class CodecProperties {
- CodecProperties(String codecName, int colorFormat) {
- this.codecName = codecName;
- this.colorFormat = colorFormat;
- }
- public boolean isGoogleCodec() {
- return codecName.toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
- }
-
- public final String codecName; // OpenMax component name for VP8 codec.
- public final int colorFormat; // Color format supported by codec.
- }
-
- /**
- * Function to find VP8 codec.
- *
- * Iterates through the list of available codecs and tries to find
- * VPX codec, which can support either YUV420 planar or NV12 color formats.
- * If forceGoogleCodec parameter set to true the function always returns
- * Google VPX codec.
- * If forceGoogleCodec parameter set to false the functions looks for platform
- * specific VPX codec first. If no platform specific codec exist, falls back to
- * Google VPX codec.
- *
- * @param isEncoder Flag if encoder is requested.
- * @param forceGoogleCodec Forces to use Google codec.
- */
- private CodecProperties getVpxCodecProperties(
- boolean isEncoder,
- MediaFormat format,
- boolean forceGoogleCodec) throws Exception {
- CodecProperties codecProperties = null;
- String mime = format.getString(MediaFormat.KEY_MIME);
-
- // Loop through the list of omx components in case platform specific codec
- // is requested.
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
- if (isEncoder != codecInfo.isEncoder()) {
- continue;
- }
- Log.v(TAG, codecInfo.getName());
- // TODO: remove dependence of Google from the test
- // Check if this is Google codec - we should ignore it.
- boolean isGoogleCodec =
- codecInfo.getName().toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
- if (!isGoogleCodec && forceGoogleCodec) {
- continue;
- }
-
- for (String type : codecInfo.getSupportedTypes()) {
- if (!type.equalsIgnoreCase(mime)) {
- continue;
- }
- CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(type);
- if (!capabilities.isFormatSupported(format)) {
- continue;
- }
-
- // Get candidate codec properties.
- Log.v(TAG, "Found candidate codec " + codecInfo.getName());
- for (int colorFormat: capabilities.colorFormats) {
- Log.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat));
- }
-
- // Check supported color formats.
- for (int supportedColorFormat : mSupportedColorList) {
- for (int codecColorFormat : capabilities.colorFormats) {
- if (codecColorFormat == supportedColorFormat) {
- codecProperties = new CodecProperties(codecInfo.getName(),
- codecColorFormat);
- Log.v(TAG, "Found target codec " + codecProperties.codecName +
- ". Color: 0x" + Integer.toHexString(codecColorFormat));
- // return first HW codec found
- if (!isGoogleCodec) {
- return codecProperties;
- }
- }
- }
- }
- }
- }
- if (codecProperties == null) {
- Log.i(TAG, "no suitable " + (forceGoogleCodec ? "google " : "")
- + (isEncoder ? "encoder " : "decoder ") + "found for " + format);
- }
- return codecProperties;
- }
-
- /**
- * Parameters for encoded video stream.
- */
- protected class EncoderOutputStreamParameters {
- // Name of raw YUV420 input file. When the value of this parameter
- // is set to null input file descriptor from inputResourceId parameter
- // is used instead.
- public String inputYuvFilename;
- // Name of scaled YUV420 input file.
- public String scaledYuvFilename;
- // File descriptor for the raw input file (YUV420). Used only if
- // inputYuvFilename parameter is null.
- int inputResourceId;
- // Name of the IVF file to write encoded bitsream
- public String outputIvfFilename;
- // Force to use Google VP8 encoder.
- boolean forceGoogleEncoder;
- // Number of frames to encode.
- int frameCount;
- // Frame rate of input file in frames per second.
- int frameRate;
- // Encoded frame width.
- public int frameWidth;
- // Encoded frame height.
- public int frameHeight;
- // Encoding bitrate array in bits/second for every frame. If array length
- // is shorter than the total number of frames, the last value is re-used for
- // all remaining frames. For constant bitrate encoding single element
- // array can be used with first element set to target bitrate value.
- public int[] bitrateSet;
- // Encoding bitrate type - VBR or CBR
- public int bitrateType;
- // Number of temporal layers
- public int temporalLayers;
- // Desired key frame interval - codec is asked to generate key frames
- // at a period defined by this parameter.
- public int syncFrameInterval;
- // Optional parameter - forced key frame interval. Used to
- // explicitly request the codec to generate key frames using
- // MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME parameter.
- public int syncForceFrameInterval;
- // Buffer timeout
- long timeoutDequeue;
- // Flag if encoder should run in Looper thread.
- boolean runInLooperThread;
- }
-
- /**
- * Generates an array of default parameters for encoder output stream based on
- * upscaling value.
- */
- protected ArrayList<EncoderOutputStreamParameters> getDefaultEncodingParameterList(
- String inputYuvName,
- String outputIvfBaseName,
- int encodeSeconds,
- int[] resolutionScales,
- int frameWidth,
- int frameHeight,
- int frameRate,
- int bitrateMode,
- int[] bitrates,
- boolean syncEncoding) {
- assertTrue(resolutionScales.length == bitrates.length);
- int numCodecs = resolutionScales.length;
- ArrayList<EncoderOutputStreamParameters> outputParameters =
- new ArrayList<EncoderOutputStreamParameters>(numCodecs);
- for (int i = 0; i < numCodecs; i++) {
- EncoderOutputStreamParameters params = new EncoderOutputStreamParameters();
- if (inputYuvName != null) {
- params.inputYuvFilename = SDCARD_DIR + File.separator + inputYuvName;
- } else {
- params.inputYuvFilename = null;
- }
- params.scaledYuvFilename = SDCARD_DIR + File.separator +
- outputIvfBaseName + resolutionScales[i]+ ".yuv";
- params.inputResourceId = R.raw.football_qvga;
- params.outputIvfFilename = SDCARD_DIR + File.separator +
- outputIvfBaseName + resolutionScales[i] + ".ivf";
- params.forceGoogleEncoder = false;
- params.frameCount = encodeSeconds * frameRate;
- params.frameRate = frameRate;
- params.frameWidth = Math.min(frameWidth * resolutionScales[i], 1280);
- params.frameHeight = Math.min(frameHeight * resolutionScales[i], 720);
- params.bitrateSet = new int[1];
- params.bitrateSet[0] = bitrates[i];
- params.bitrateType = bitrateMode;
- params.temporalLayers = 0;
- params.syncFrameInterval = SYNC_FRAME_INTERVAL;
- params.syncForceFrameInterval = 0;
- if (syncEncoding) {
- params.timeoutDequeue = DEFAULT_DEQUEUE_TIMEOUT_US;
- params.runInLooperThread = false;
- } else {
- params.timeoutDequeue = 0;
- params.runInLooperThread = true;
- }
- outputParameters.add(params);
- }
- return outputParameters;
- }
-
- protected EncoderOutputStreamParameters getDefaultEncodingParameters(
- String inputYuvName,
- String outputIvfBaseName,
- int encodeSeconds,
- int frameWidth,
- int frameHeight,
- int frameRate,
- int bitrateMode,
- int bitrate,
- boolean syncEncoding) {
- int[] scaleValues = { 1 };
- int[] bitrates = { bitrate };
- return getDefaultEncodingParameterList(
- inputYuvName,
- outputIvfBaseName,
- encodeSeconds,
- scaleValues,
- frameWidth,
- frameHeight,
- frameRate,
- bitrateMode,
- bitrates,
- syncEncoding).get(0);
- }
-
- /**
- * Converts (interleaves) YUV420 planar to NV12.
- * Assumes packed, macroblock-aligned frame with no cropping
- * (visible/coded row length == stride).
- */
- private static byte[] YUV420ToNV(int width, int height, byte[] yuv) {
- byte[] nv = new byte[yuv.length];
- // Y plane we just copy.
- System.arraycopy(yuv, 0, nv, 0, width * height);
-
- // U & V plane we interleave.
- int u_offset = width * height;
- int v_offset = u_offset + u_offset / 4;
- int nv_offset = width * height;
- for (int i = 0; i < width * height / 4; i++) {
- nv[nv_offset++] = yuv[u_offset++];
- nv[nv_offset++] = yuv[v_offset++];
- }
- return nv;
- }
-
- /**
- * Converts (de-interleaves) NV12 to YUV420 planar.
- * Stride may be greater than width, slice height may be greater than height.
- */
- private static byte[] NV12ToYUV420(int width, int height,
- int stride, int sliceHeight, byte[] nv12) {
- byte[] yuv = new byte[width * height * 3 / 2];
-
- // Y plane we just copy.
- for (int i = 0; i < height; i++) {
- System.arraycopy(nv12, i * stride, yuv, i * width, width);
- }
-
- // U & V plane - de-interleave.
- int u_offset = width * height;
- int v_offset = u_offset + u_offset / 4;
- int nv_offset;
- for (int i = 0; i < height / 2; i++) {
- nv_offset = stride * (sliceHeight + i);
- for (int j = 0; j < width / 2; j++) {
- yuv[u_offset++] = nv12[nv_offset++];
- yuv[v_offset++] = nv12[nv_offset++];
- }
- }
- return yuv;
- }
-
- /**
- * Packs YUV420 frame by moving it to a smaller size buffer with stride and slice
- * height equal to the original frame width and height.
- */
- private static byte[] PackYUV420(int width, int height,
- int stride, int sliceHeight, byte[] src) {
- byte[] dst = new byte[width * height * 3 / 2];
- // Y copy.
- for (int i = 0; i < height; i++) {
- System.arraycopy(src, i * stride, dst, i * width, width);
- }
- // U and V copy.
- int u_src_offset = stride * sliceHeight;
- int v_src_offset = u_src_offset + u_src_offset / 4;
- int u_dst_offset = width * height;
- int v_dst_offset = u_dst_offset + u_dst_offset / 4;
- for (int i = 0; i < height / 2; i++) {
- System.arraycopy(src, u_src_offset + i * (stride / 2),
- dst, u_dst_offset + i * (width / 2), width / 2);
- System.arraycopy(src, v_src_offset + i * (stride / 2),
- dst, v_dst_offset + i * (width / 2), width / 2);
- }
- return dst;
- }
-
-
- private static void imageUpscale1To2(byte[] src, int srcByteOffset, int srcStride,
- byte[] dst, int dstByteOffset, int dstWidth, int dstHeight) {
- for (int i = 0; i < dstHeight/2 - 1; i++) {
- int dstOffset0 = 2 * i * dstWidth + dstByteOffset;
- int dstOffset1 = dstOffset0 + dstWidth;
- int srcOffset0 = i * srcStride + srcByteOffset;
- int srcOffset1 = srcOffset0 + srcStride;
- int pixel00 = (int)src[srcOffset0++] & 0xff;
- int pixel10 = (int)src[srcOffset1++] & 0xff;
- for (int j = 0; j < dstWidth/2 - 1; j++) {
- int pixel01 = (int)src[srcOffset0++] & 0xff;
- int pixel11 = (int)src[srcOffset1++] & 0xff;
- dst[dstOffset0++] = (byte)pixel00;
- dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
- dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
- dst[dstOffset1++] = (byte)((pixel00 + pixel01 + pixel10 + pixel11 + 2) / 4);
- pixel00 = pixel01;
- pixel10 = pixel11;
- }
- // last column
- dst[dstOffset0++] = (byte)pixel00;
- dst[dstOffset0++] = (byte)pixel00;
- dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
- dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
- }
-
- // last row
- int dstOffset0 = (dstHeight - 2) * dstWidth + dstByteOffset;
- int dstOffset1 = dstOffset0 + dstWidth;
- int srcOffset0 = (dstHeight/2 - 1) * srcStride + srcByteOffset;
- int pixel00 = (int)src[srcOffset0++] & 0xff;
- for (int j = 0; j < dstWidth/2 - 1; j++) {
- int pixel01 = (int)src[srcOffset0++] & 0xff;
- dst[dstOffset0++] = (byte)pixel00;
- dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
- dst[dstOffset1++] = (byte)pixel00;
- dst[dstOffset1++] = (byte)((pixel00 + pixel01 + 1) / 2);
- pixel00 = pixel01;
- }
- // the very last pixel - bottom right
- dst[dstOffset0++] = (byte)pixel00;
- dst[dstOffset0++] = (byte)pixel00;
- dst[dstOffset1++] = (byte)pixel00;
- dst[dstOffset1++] = (byte)pixel00;
- }
-
- /**
- * Up-scale image.
- * Scale factor is defined by source and destination width ratio.
- * Only 1:2 and 1:4 up-scaling is supported for now.
- * For 640x480 -> 1280x720 conversion only top 640x360 part of the original
- * image is scaled.
- */
- private static byte[] imageScale(byte[] src, int srcWidth, int srcHeight,
- int dstWidth, int dstHeight) throws Exception {
- int srcYSize = srcWidth * srcHeight;
- int dstYSize = dstWidth * dstHeight;
- byte[] dst = null;
- if (dstWidth == 2 * srcWidth && dstHeight <= 2 * srcHeight) {
- // 1:2 upscale
- dst = new byte[dstWidth * dstHeight * 3 / 2];
- imageUpscale1To2(src, 0, srcWidth,
- dst, 0, dstWidth, dstHeight); // Y
- imageUpscale1To2(src, srcYSize, srcWidth / 2,
- dst, dstYSize, dstWidth / 2, dstHeight / 2); // U
- imageUpscale1To2(src, srcYSize * 5 / 4, srcWidth / 2,
- dst, dstYSize * 5 / 4, dstWidth / 2, dstHeight / 2); // V
- } else if (dstWidth == 4 * srcWidth && dstHeight <= 4 * srcHeight) {
- // 1:4 upscale - in two steps
- int midWidth = 2 * srcWidth;
- int midHeight = 2 * srcHeight;
- byte[] midBuffer = imageScale(src, srcWidth, srcHeight, midWidth, midHeight);
- dst = imageScale(midBuffer, midWidth, midHeight, dstWidth, dstHeight);
-
- } else {
- throw new RuntimeException("Can not find proper scaling function");
- }
-
- return dst;
- }
-
- private void cacheScaledImage(
- String srcYuvFilename, int srcResourceId, int srcFrameWidth, int srcFrameHeight,
- String dstYuvFilename, int dstFrameWidth, int dstFrameHeight) throws Exception {
- InputStream srcStream = OpenFileOrResourceId(srcYuvFilename, srcResourceId);
- FileOutputStream dstFile = new FileOutputStream(dstYuvFilename, false);
- int srcFrameSize = srcFrameWidth * srcFrameHeight * 3 / 2;
- byte[] srcFrame = new byte[srcFrameSize];
- byte[] dstFrame = null;
- Log.d(TAG, "Scale to " + dstFrameWidth + " x " + dstFrameHeight + ". -> " + dstYuvFilename);
- while (true) {
- int bytesRead = srcStream.read(srcFrame);
- if (bytesRead != srcFrame.length) {
- break;
- }
- if (dstFrameWidth == srcFrameWidth && dstFrameHeight == srcFrameHeight) {
- dstFrame = srcFrame;
- } else {
- dstFrame = imageScale(srcFrame, srcFrameWidth, srcFrameHeight,
- dstFrameWidth, dstFrameHeight);
- }
- dstFile.write(dstFrame);
- }
- srcStream.close();
- dstFile.close();
- }
-
-
- /**
- * A basic check if an encoded stream is decodable.
- *
- * The most basic confirmation we can get about a frame
- * being properly encoded is trying to decode it.
- * (Especially in realtime mode encode output is non-
- * deterministic, therefore a more thorough check like
- * md5 sum comparison wouldn't work.)
- *
- * Indeed, MediaCodec will raise an IllegalStateException
- * whenever vp8 decoder fails to decode a frame, and
- * this test uses that fact to verify the bitstream.
- *
- * @param inputIvfFilename The name of the IVF file containing encoded bitsream.
- * @param outputYuvFilename The name of the output YUV file (optional).
- * @param frameRate Frame rate of input file in frames per second
- * @param forceGoogleDecoder Force to use Google VP8 decoder.
- */
- protected ArrayList<MediaCodec.BufferInfo> decode(
- String inputIvfFilename,
- String outputYuvFilename,
- int frameRate,
- boolean forceGoogleDecoder) throws Exception {
- ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
-
- // Open input/output.
- IvfReader ivf = new IvfReader(inputIvfFilename);
- int frameWidth = ivf.getWidth();
- int frameHeight = ivf.getHeight();
- int frameCount = ivf.getFrameCount();
- int frameStride = frameWidth;
- int frameSliceHeight = frameHeight;
- assertTrue(frameWidth > 0);
- assertTrue(frameHeight > 0);
- assertTrue(frameCount > 0);
-
- // Create decoder.
- MediaFormat format = MediaFormat.createVideoFormat(
- VP8_MIME, ivf.getWidth(), ivf.getHeight());
- CodecProperties properties = getVpxCodecProperties(
- false /* encoder */, format, forceGoogleDecoder);
- if (properties == null) {
- ivf.close();
- return null;
- }
- int frameColorFormat = properties.colorFormat;
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
-
- FileOutputStream yuv = null;
- if (outputYuvFilename != null) {
- yuv = new FileOutputStream(outputYuvFilename, false);
- }
-
- Log.d(TAG, "Creating decoder " + properties.codecName +
- ". Color format: 0x" + Integer.toHexString(frameColorFormat) +
- ". " + frameWidth + " x " + frameHeight);
- Log.d(TAG, " Format: " + format);
- Log.d(TAG, " In: " + inputIvfFilename + ". Out:" + outputYuvFilename);
- MediaCodec decoder = MediaCodec.createByCodecName(properties.codecName);
- decoder.configure(format,
- null, // surface
- null, // crypto
- 0); // flags
- decoder.start();
-
- ByteBuffer[] inputBuffers = decoder.getInputBuffers();
- ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
- MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
-
- // decode loop
- int inputFrameIndex = 0;
- int outputFrameIndex = 0;
- long inPresentationTimeUs = 0;
- long outPresentationTimeUs = 0;
- boolean sawOutputEOS = false;
- boolean sawInputEOS = false;
-
- while (!sawOutputEOS) {
- if (!sawInputEOS) {
- int inputBufIndex = decoder.dequeueInputBuffer(DEFAULT_DEQUEUE_TIMEOUT_US);
- if (inputBufIndex >= 0) {
- byte[] frame = ivf.readFrame(inputFrameIndex);
-
- if (inputFrameIndex == frameCount - 1) {
- Log.d(TAG, " Input EOS for frame # " + inputFrameIndex);
- sawInputEOS = true;
- }
-
- inputBuffers[inputBufIndex].clear();
- inputBuffers[inputBufIndex].put(frame);
- inputBuffers[inputBufIndex].rewind();
- inPresentationTimeUs = (inputFrameIndex * 1000000) / frameRate;
-
- decoder.queueInputBuffer(
- inputBufIndex,
- 0, // offset
- frame.length,
- inPresentationTimeUs,
- sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-
- inputFrameIndex++;
- }
- }
-
- int result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
- while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
- result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- outputBuffers = decoder.getOutputBuffers();
- } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- // Process format change
- format = decoder.getOutputFormat();
- frameWidth = format.getInteger(MediaFormat.KEY_WIDTH);
- frameHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
- frameColorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
- Log.d(TAG, "Decoder output format change. Color: 0x" +
- Integer.toHexString(frameColorFormat));
- Log.d(TAG, "Format: " + format.toString());
-
- // Parse frame and slice height from undocumented values
- if (format.containsKey("stride")) {
- frameStride = format.getInteger("stride");
- } else {
- frameStride = frameWidth;
- }
- if (format.containsKey("slice-height")) {
- frameSliceHeight = format.getInteger("slice-height");
- } else {
- frameSliceHeight = frameHeight;
- }
- Log.d(TAG, "Frame stride and slice height: " + frameStride +
- " x " + frameSliceHeight);
- frameStride = Math.max(frameWidth, frameStride);
- frameSliceHeight = Math.max(frameHeight, frameSliceHeight);
- }
- result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
- }
- if (result >= 0) {
- int outputBufIndex = result;
- outPresentationTimeUs = bufferInfo.presentationTimeUs;
- Log.v(TAG, "Writing buffer # " + outputFrameIndex +
- ". Size: " + bufferInfo.size +
- ". InTime: " + (inPresentationTimeUs + 500)/1000 +
- ". OutTime: " + (outPresentationTimeUs + 500)/1000);
- if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- sawOutputEOS = true;
- Log.d(TAG, " Output EOS for frame # " + outputFrameIndex);
- }
-
- if (bufferInfo.size > 0) {
- // Save decoder output to yuv file.
- if (yuv != null) {
- byte[] frame = new byte[bufferInfo.size];
- outputBuffers[outputBufIndex].position(bufferInfo.offset);
- outputBuffers[outputBufIndex].get(frame, 0, bufferInfo.size);
- // Convert NV12 to YUV420 if necessary.
- if (frameColorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
- frame = NV12ToYUV420(frameWidth, frameHeight,
- frameStride, frameSliceHeight, frame);
- }
- int writeLength = Math.min(frameWidth * frameHeight * 3 / 2, frame.length);
- // Pack frame if necessary.
- if (writeLength < frame.length &&
- (frameStride > frameWidth || frameSliceHeight > frameHeight)) {
- frame = PackYUV420(frameWidth, frameHeight,
- frameStride, frameSliceHeight, frame);
- }
- yuv.write(frame, 0, writeLength);
- }
- outputFrameIndex++;
-
- // Update statistics - store presentation time delay in offset
- long presentationTimeUsDelta = inPresentationTimeUs - outPresentationTimeUs;
- MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
- bufferInfoCopy.set((int)presentationTimeUsDelta, bufferInfo.size,
- outPresentationTimeUs, bufferInfo.flags);
- bufferInfos.add(bufferInfoCopy);
- }
- decoder.releaseOutputBuffer(outputBufIndex, false);
- }
- }
- decoder.stop();
- decoder.release();
- ivf.close();
- if (yuv != null) {
- yuv.close();
- }
-
- return bufferInfos;
- }
-
-
- /**
- * Helper function to return InputStream from either filename (if set)
- * or resource id (if filename is not set).
- */
- private InputStream OpenFileOrResourceId(String filename, int resourceId) throws Exception {
- if (filename != null) {
- return new FileInputStream(filename);
- }
- return mResources.openRawResource(resourceId);
- }
-
- /**
- * Results of frame encoding.
- */
- protected class MediaEncoderOutput {
- public long inPresentationTimeUs;
- public long outPresentationTimeUs;
- public boolean outputGenerated;
- public int flags;
- public byte[] buffer;
- }
-
- protected class MediaEncoderAsyncHelper {
- private final EncoderOutputStreamParameters mStreamParams;
- private final CodecProperties mProperties;
- private final ArrayList<MediaCodec.BufferInfo> mBufferInfos;
- private final IvfWriter mIvf;
- private final byte[] mSrcFrame;
-
- private InputStream mYuvStream;
- private int mInputFrameIndex;
-
- MediaEncoderAsyncHelper(
- EncoderOutputStreamParameters streamParams,
- CodecProperties properties,
- ArrayList<MediaCodec.BufferInfo> bufferInfos,
- IvfWriter ivf)
- throws Exception {
- mStreamParams = streamParams;
- mProperties = properties;
- mBufferInfos = bufferInfos;
- mIvf = ivf;
-
- int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
- mSrcFrame = new byte[srcFrameSize];
-
- mYuvStream = OpenFileOrResourceId(
- streamParams.inputYuvFilename, streamParams.inputResourceId);
- }
-
- public byte[] getInputFrame() {
- // Check EOS
- if (mStreamParams.frameCount == 0
- || (mStreamParams.frameCount > 0
- && mInputFrameIndex >= mStreamParams.frameCount)) {
- Log.d(TAG, "---Sending EOS empty frame for frame # " + mInputFrameIndex);
- return null;
- }
-
- try {
- int bytesRead = mYuvStream.read(mSrcFrame);
-
- if (bytesRead == -1) {
- // rewind to beginning of file
- mYuvStream.close();
- mYuvStream = OpenFileOrResourceId(
- mStreamParams.inputYuvFilename, mStreamParams.inputResourceId);
- bytesRead = mYuvStream.read(mSrcFrame);
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to read YUV file.");
- return null;
- }
- mInputFrameIndex++;
-
- // Convert YUV420 to NV12 if necessary
- if (mProperties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
- return YUV420ToNV(mStreamParams.frameWidth, mStreamParams.frameHeight,
- mSrcFrame);
- } else {
- return mSrcFrame;
- }
- }
-
- public boolean saveOutputFrame(MediaEncoderOutput out) {
- if (out.outputGenerated) {
- if (out.buffer.length > 0) {
- // Save frame
- try {
- mIvf.writeFrame(out.buffer, out.outPresentationTimeUs);
- } catch (Exception e) {
- Log.d(TAG, "Failed to write frame");
- return true;
- }
-
- // Update statistics - store presentation time delay in offset
- long presentationTimeUsDelta = out.inPresentationTimeUs -
- out.outPresentationTimeUs;
- MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
- bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
- out.outPresentationTimeUs, out.flags);
- mBufferInfos.add(bufferInfoCopy);
- }
- // Detect output EOS
- if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- Log.d(TAG, "----Output EOS ");
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * Video encoder wrapper class.
- * Allows to run the encoder either in a callee's thread or in a looper thread
- * using buffer dequeue ready notification callbacks.
- *
- * Function feedInput() is used to send raw video frame to the encoder input. When encoder
- * is configured to run in async mode the function will run in a looper thread.
- * Encoded frame can be retrieved by calling getOutput() function.
- */
- protected class MediaEncoderAsync extends Thread {
- private int mId;
- private MediaCodec mCodec;
- private MediaFormat mFormat;
- private ByteBuffer[] mInputBuffers;
- private ByteBuffer[] mOutputBuffers;
- private int mInputFrameIndex;
- private int mOutputFrameIndex;
- private int mInputBufIndex;
- private int mFrameRate;
- private long mTimeout;
- private MediaCodec.BufferInfo mBufferInfo;
- private long mInPresentationTimeUs;
- private long mOutPresentationTimeUs;
- private boolean mAsync;
- // Flag indicating if input frame was consumed by the encoder in feedInput() call.
- private boolean mConsumedInput;
- // Result of frame encoding returned by getOutput() call.
- private MediaEncoderOutput mOutput;
- // Object used to signal that looper thread has started and Handler instance associated
- // with looper thread has been allocated.
- private final Object mThreadEvent = new Object();
- // Object used to signal that MediaCodec buffer dequeue notification callback
- // was received.
- private final Object mCallbackEvent = new Object();
- private Handler mHandler;
- private boolean mCallbackReceived;
- private MediaEncoderAsyncHelper mHelper;
- private final Object mCompletionEvent = new Object();
- private boolean mCompleted;
-
- private MediaCodec.Callback mCallback = new MediaCodec.Callback() {
- @Override
- public void onInputBufferAvailable(MediaCodec codec, int index) {
- if (mHelper == null) {
- Log.e(TAG, "async helper not available");
- return;
- }
-
- byte[] encFrame = mHelper.getInputFrame();
- boolean inputEOS = (encFrame == null);
-
- int encFrameLength = 0;
- int flags = 0;
- if (inputEOS) {
- flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
- } else {
- encFrameLength = encFrame.length;
-
- ByteBuffer byteBuffer = mCodec.getInputBuffer(index);
- byteBuffer.put(encFrame);
- byteBuffer.rewind();
-
- mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
-
- Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
- ". InTime: " + (mInPresentationTimeUs + 500)/1000);
-
- mInputFrameIndex++;
- }
-
- mCodec.queueInputBuffer(
- index,
- 0, // offset
- encFrameLength, // size
- mInPresentationTimeUs,
- flags);
- }
-
- @Override
- public void onOutputBufferAvailable(MediaCodec codec,
- int index, MediaCodec.BufferInfo info) {
- if (mHelper == null) {
- Log.e(TAG, "async helper not available");
- return;
- }
-
- MediaEncoderOutput out = new MediaEncoderOutput();
-
- out.buffer = new byte[info.size];
- ByteBuffer outputBuffer = mCodec.getOutputBuffer(index);
- outputBuffer.get(out.buffer, 0, info.size);
- mOutPresentationTimeUs = info.presentationTimeUs;
-
- String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
- if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
- logStr += " CONFIG. ";
- }
- if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
- logStr += " KEY. ";
- }
- if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- logStr += " EOS. ";
- }
- logStr += " Size: " + info.size;
- logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
- ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
- Log.v(TAG, logStr);
-
- if (mOutputFrameIndex == 0 &&
- ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
- throw new RuntimeException("First frame is not a sync frame.");
- }
-
- if (info.size > 0) {
- mOutputFrameIndex++;
- out.inPresentationTimeUs = mInPresentationTimeUs;
- out.outPresentationTimeUs = mOutPresentationTimeUs;
- }
- mCodec.releaseOutputBuffer(index, false);
-
- out.flags = info.flags;
- out.outputGenerated = true;
-
- if (mHelper.saveOutputFrame(out)) {
- // output EOS
- signalCompletion();
- }
- }
-
- @Override
- public void onError(MediaCodec codec, CodecException e) {
- Log.e(TAG, "onError: " + e
- + ", transient " + e.isTransient()
- + ", recoverable " + e.isRecoverable()
- + ", error " + e.getErrorCode());
- }
-
- @Override
- public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
- Log.i(TAG, "onOutputFormatChanged: " + format.toString());
- }
- };
-
- private synchronized void requestStart() throws Exception {
- mHandler = null;
- start();
- // Wait for Hander allocation
- synchronized (mThreadEvent) {
- while (mHandler == null) {
- mThreadEvent.wait();
- }
- }
- }
-
- public void setAsyncHelper(MediaEncoderAsyncHelper helper) {
- mHelper = helper;
- }
-
- @Override
- public void run() {
- Looper.prepare();
- synchronized (mThreadEvent) {
- mHandler = new Handler();
- mThreadEvent.notify();
- }
- Looper.loop();
- }
-
- private void runCallable(final Callable<?> callable) throws Exception {
- if (mAsync) {
- final Exception[] exception = new Exception[1];
- final CountDownLatch countDownLatch = new CountDownLatch(1);
- mHandler.post( new Runnable() {
- @Override
- public void run() {
- try {
- callable.call();
- } catch (Exception e) {
- exception[0] = e;
- } finally {
- countDownLatch.countDown();
- }
- }
- } );
-
- // Wait for task completion
- countDownLatch.await();
- if (exception[0] != null) {
- throw exception[0];
- }
- } else {
- callable.call();
- }
- }
-
- private synchronized void requestStop() throws Exception {
- mHandler.post( new Runnable() {
- @Override
- public void run() {
- // This will run on the Looper thread
- Log.v(TAG, "MediaEncoder looper quitting");
- Looper.myLooper().quitSafely();
- }
- } );
- // Wait for completion
- join();
- mHandler = null;
- }
-
- private void createCodecInternal(final String name,
- final MediaFormat format, final long timeout) throws Exception {
- mBufferInfo = new MediaCodec.BufferInfo();
- mFormat = format;
- mFrameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
- mTimeout = timeout;
- mInputFrameIndex = 0;
- mOutputFrameIndex = 0;
- mInPresentationTimeUs = 0;
- mOutPresentationTimeUs = 0;
-
- mCodec = MediaCodec.createByCodecName(name);
- if (mAsync) {
- mCodec.setCallback(mCallback);
- }
- mCodec.configure(mFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
- mCodec.start();
-
- // get the cached input/output only in sync mode
- if (!mAsync) {
- mInputBuffers = mCodec.getInputBuffers();
- mOutputBuffers = mCodec.getOutputBuffers();
- }
- }
-
- public void createCodec(int id, final String name, final MediaFormat format,
- final long timeout, boolean async) throws Exception {
- mId = id;
- mAsync = async;
- if (mAsync) {
- requestStart(); // start looper thread
- }
- runCallable( new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- createCodecInternal(name, format, timeout);
- return null;
- }
- } );
- }
-
- private void feedInputInternal(final byte[] encFrame, final boolean inputEOS) {
- mConsumedInput = false;
- // Feed input
- mInputBufIndex = mCodec.dequeueInputBuffer(mTimeout);
-
- if (mInputBufIndex >= 0) {
- mInputBuffers[mInputBufIndex].clear();
- mInputBuffers[mInputBufIndex].put(encFrame);
- mInputBuffers[mInputBufIndex].rewind();
- int encFrameLength = encFrame.length;
- int flags = 0;
- if (inputEOS) {
- encFrameLength = 0;
- flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
- }
- if (!inputEOS) {
- Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
- ". InTime: " + (mInPresentationTimeUs + 500)/1000);
- mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
- mInputFrameIndex++;
- }
-
- mCodec.queueInputBuffer(
- mInputBufIndex,
- 0, // offset
- encFrameLength, // size
- mInPresentationTimeUs,
- flags);
-
- mConsumedInput = true;
- } else {
- Log.v(TAG, "In " + mId + " - TRY_AGAIN_LATER");
- }
- mCallbackReceived = false;
- }
-
- public boolean feedInput(final byte[] encFrame, final boolean inputEOS) throws Exception {
- runCallable( new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- feedInputInternal(encFrame, inputEOS);
- return null;
- }
- } );
- return mConsumedInput;
- }
-
- private void getOutputInternal() {
- mOutput = new MediaEncoderOutput();
- mOutput.inPresentationTimeUs = mInPresentationTimeUs;
- mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
- mOutput.outputGenerated = false;
-
- // Get output from the encoder
- int result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
- while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
- result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- mOutputBuffers = mCodec.getOutputBuffers();
- } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- mFormat = mCodec.getOutputFormat();
- Log.d(TAG, "Format changed: " + mFormat.toString());
- }
- result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
- }
- if (result == MediaCodec.INFO_TRY_AGAIN_LATER) {
- Log.v(TAG, "Out " + mId + " - TRY_AGAIN_LATER");
- }
-
- if (result >= 0) {
- int outputBufIndex = result;
- mOutput.buffer = new byte[mBufferInfo.size];
- mOutputBuffers[outputBufIndex].position(mBufferInfo.offset);
- mOutputBuffers[outputBufIndex].get(mOutput.buffer, 0, mBufferInfo.size);
- mOutPresentationTimeUs = mBufferInfo.presentationTimeUs;
-
- String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
- if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
- logStr += " CONFIG. ";
- }
- if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
- logStr += " KEY. ";
- }
- if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- logStr += " EOS. ";
- }
- logStr += " Size: " + mBufferInfo.size;
- logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
- ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
- Log.v(TAG, logStr);
- if (mOutputFrameIndex == 0 &&
- ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
- throw new RuntimeException("First frame is not a sync frame.");
- }
-
- if (mBufferInfo.size > 0) {
- mOutputFrameIndex++;
- mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
- }
- mCodec.releaseOutputBuffer(outputBufIndex, false);
-
- mOutput.flags = mBufferInfo.flags;
- mOutput.outputGenerated = true;
- }
- mCallbackReceived = false;
- }
-
- public MediaEncoderOutput getOutput() throws Exception {
- runCallable( new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- getOutputInternal();
- return null;
- }
- } );
- return mOutput;
- }
-
- public void forceSyncFrame() throws Exception {
- final Bundle syncFrame = new Bundle();
- syncFrame.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
- runCallable( new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- mCodec.setParameters(syncFrame);
- return null;
- }
- } );
- }
-
- public void updateBitrate(int bitrate) throws Exception {
- final Bundle bitrateUpdate = new Bundle();
- bitrateUpdate.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bitrate);
- runCallable( new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- mCodec.setParameters(bitrateUpdate);
- return null;
- }
- } );
- }
-
-
- public void waitForBufferEvent() throws Exception {
- Log.v(TAG, "----Enc" + mId + " waiting for bufferEvent");
- if (mAsync) {
- synchronized (mCallbackEvent) {
- if (!mCallbackReceived) {
- mCallbackEvent.wait(1000); // wait 1 sec for a callback
- // throw an exception if callback was not received
- if (!mCallbackReceived) {
- throw new RuntimeException("MediaCodec callback was not received");
- }
- }
- }
- } else {
- Thread.sleep(5);
- }
- Log.v(TAG, "----Waiting for bufferEvent done");
- }
-
-
- public void waitForCompletion(long timeoutMs) throws Exception {
- synchronized (mCompletionEvent) {
- long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
-
- while (!mCompleted) {
- mCompletionEvent.wait(timeoutExpiredMs - System.currentTimeMillis());
- if (System.currentTimeMillis() >= timeoutExpiredMs) {
- throw new RuntimeException("encoding has timed out!");
- }
- }
- }
- }
-
- public void signalCompletion() {
- synchronized (mCompletionEvent) {
- mCompleted = true;
- mCompletionEvent.notify();
- }
- }
-
- public void deleteCodec() throws Exception {
- runCallable( new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- mCodec.stop();
- mCodec.release();
- return null;
- }
- } );
- if (mAsync) {
- requestStop(); // Stop looper thread
- }
- }
- }
-
- /**
- * Vp8 encoding loop supporting encoding single streams with an option
- * to run in a looper thread and use buffer ready notification callbacks.
- *
- * Output stream is described by encodingParams parameters.
- *
- * MediaCodec will raise an IllegalStateException
- * whenever vp8 encoder fails to encode a frame.
- *
- * Color format of input file should be YUV420, and frameWidth,
- * frameHeight should be supplied correctly as raw input file doesn't
- * include any header data.
- *
- * @param streamParams Structure with encoder parameters
- * @return Returns array of encoded frames information for each frame.
- */
- protected ArrayList<MediaCodec.BufferInfo> encode(
- EncoderOutputStreamParameters streamParams) throws Exception {
-
- ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
- Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
- streamParams.frameHeight);
- int bitrate = streamParams.bitrateSet[0];
-
- // Create minimal media format signifying desired output.
- MediaFormat format = MediaFormat.createVideoFormat(
- VP8_MIME, streamParams.frameWidth, streamParams.frameHeight);
- format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
- CodecProperties properties = getVpxCodecProperties(
- true, format, streamParams.forceGoogleEncoder);
- if (properties == null) {
- return null;
- }
-
- // Open input/output
- InputStream yuvStream = OpenFileOrResourceId(
- streamParams.inputYuvFilename, streamParams.inputResourceId);
- IvfWriter ivf = new IvfWriter(
- streamParams.outputIvfFilename, streamParams.frameWidth, streamParams.frameHeight);
-
- // Create a media format signifying desired output.
- if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
- format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
- }
- if (streamParams.temporalLayers > 0) {
- format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
- }
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
- format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
- int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
- streamParams.frameRate;
- format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
-
- // Create encoder
- Log.d(TAG, "Creating encoder " + properties.codecName +
- ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
- streamParams.frameWidth + " x " + streamParams.frameHeight +
- ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
- ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
- ". Key frame:" + syncFrameInterval * streamParams.frameRate +
- ". Force keyFrame: " + streamParams.syncForceFrameInterval);
- Log.d(TAG, " Format: " + format);
- Log.d(TAG, " Output ivf:" + streamParams.outputIvfFilename);
- MediaEncoderAsync codec = new MediaEncoderAsync();
- codec.createCodec(0, properties.codecName, format,
- streamParams.timeoutDequeue, streamParams.runInLooperThread);
-
- // encode loop
- boolean sawInputEOS = false; // no more data
- boolean consumedInputEOS = false; // EOS flag is consumed dy encoder
- boolean sawOutputEOS = false;
- boolean inputConsumed = true;
- int inputFrameIndex = 0;
- int lastBitrate = bitrate;
- int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
- byte[] srcFrame = new byte[srcFrameSize];
-
- while (!sawOutputEOS) {
-
- // Read and feed input frame
- if (!consumedInputEOS) {
-
- // Read new input buffers - if previous input was consumed and no EOS
- if (inputConsumed && !sawInputEOS) {
- int bytesRead = yuvStream.read(srcFrame);
-
- // Check EOS
- if (streamParams.frameCount > 0 && inputFrameIndex >= streamParams.frameCount) {
- sawInputEOS = true;
- Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
- }
-
- if (!sawInputEOS && bytesRead == -1) {
- if (streamParams.frameCount == 0) {
- sawInputEOS = true;
- Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
- } else {
- yuvStream.close();
- yuvStream = OpenFileOrResourceId(
- streamParams.inputYuvFilename, streamParams.inputResourceId);
- bytesRead = yuvStream.read(srcFrame);
- }
- }
-
- // Force sync frame if syncForceFrameinterval is set.
- if (!sawInputEOS && inputFrameIndex > 0 &&
- streamParams.syncForceFrameInterval > 0 &&
- (inputFrameIndex % streamParams.syncForceFrameInterval) == 0) {
- Log.d(TAG, "---Requesting sync frame # " + inputFrameIndex);
- codec.forceSyncFrame();
- }
-
- // Dynamic bitrate change.
- if (!sawInputEOS && streamParams.bitrateSet.length > inputFrameIndex) {
- int newBitrate = streamParams.bitrateSet[inputFrameIndex];
- if (newBitrate != lastBitrate) {
- Log.d(TAG, "--- Requesting new bitrate " + newBitrate +
- " for frame " + inputFrameIndex);
- codec.updateBitrate(newBitrate);
- lastBitrate = newBitrate;
- }
- }
-
- // Convert YUV420 to NV12 if necessary
- if (properties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
- srcFrame = YUV420ToNV(streamParams.frameWidth, streamParams.frameHeight,
- srcFrame);
- }
- }
-
- inputConsumed = codec.feedInput(srcFrame, sawInputEOS);
- if (inputConsumed) {
- inputFrameIndex++;
- consumedInputEOS = sawInputEOS;
- }
- }
-
- // Get output from the encoder
- MediaEncoderOutput out = codec.getOutput();
- if (out.outputGenerated) {
- // Detect output EOS
- if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- Log.d(TAG, "----Output EOS ");
- sawOutputEOS = true;
- }
-
- if (out.buffer.length > 0) {
- // Save frame
- ivf.writeFrame(out.buffer, out.outPresentationTimeUs);
-
- // Update statistics - store presentation time delay in offset
- long presentationTimeUsDelta = out.inPresentationTimeUs -
- out.outPresentationTimeUs;
- MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
- bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
- out.outPresentationTimeUs, out.flags);
- bufferInfos.add(bufferInfoCopy);
- }
- }
-
- // If codec is not ready to accept input/poutput - wait for buffer ready callback
- if ((!inputConsumed || consumedInputEOS) && !out.outputGenerated) {
- codec.waitForBufferEvent();
- }
- }
-
- codec.deleteCodec();
- ivf.close();
- yuvStream.close();
-
- return bufferInfos;
- }
-
- /**
- * Vp8 encoding run in a looper thread and use buffer ready callbacks.
- *
- * Output stream is described by encodingParams parameters.
- *
- * MediaCodec will raise an IllegalStateException
- * whenever vp8 encoder fails to encode a frame.
- *
- * Color format of input file should be YUV420, and frameWidth,
- * frameHeight should be supplied correctly as raw input file doesn't
- * include any header data.
- *
- * @param streamParams Structure with encoder parameters
- * @return Returns array of encoded frames information for each frame.
- */
- protected ArrayList<MediaCodec.BufferInfo> encodeAsync(
- EncoderOutputStreamParameters streamParams) throws Exception {
- if (!streamParams.runInLooperThread) {
- throw new RuntimeException("encodeAsync should run with a looper thread!");
- }
-
- ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
- Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
- streamParams.frameHeight);
- int bitrate = streamParams.bitrateSet[0];
-
- // Create minimal media format signifying desired output.
- MediaFormat format = MediaFormat.createVideoFormat(
- VP8_MIME, streamParams.frameWidth, streamParams.frameHeight);
- format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
- CodecProperties properties = getVpxCodecProperties(
- true, format, streamParams.forceGoogleEncoder);
- if (properties == null) {
- return null;
- }
-
- // Open input/output
- IvfWriter ivf = new IvfWriter(
- streamParams.outputIvfFilename, streamParams.frameWidth, streamParams.frameHeight);
-
- // Create a media format signifying desired output.
- if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
- format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
- }
- if (streamParams.temporalLayers > 0) {
- format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
- }
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
- format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
- int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
- streamParams.frameRate;
- format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
-
- // Create encoder
- Log.d(TAG, "Creating encoder " + properties.codecName +
- ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
- streamParams.frameWidth + " x " + streamParams.frameHeight +
- ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
- ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
- ". Key frame:" + syncFrameInterval * streamParams.frameRate +
- ". Force keyFrame: " + streamParams.syncForceFrameInterval);
- Log.d(TAG, " Format: " + format);
- Log.d(TAG, " Output ivf:" + streamParams.outputIvfFilename);
-
- MediaEncoderAsync codec = new MediaEncoderAsync();
- MediaEncoderAsyncHelper helper = new MediaEncoderAsyncHelper(
- streamParams, properties, bufferInfos, ivf);
-
- codec.setAsyncHelper(helper);
- codec.createCodec(0, properties.codecName, format,
- streamParams.timeoutDequeue, streamParams.runInLooperThread);
- codec.waitForCompletion(DEFAULT_ENCODE_TIMEOUT_MS);
-
- codec.deleteCodec();
- ivf.close();
-
- return bufferInfos;
- }
-
- /**
- * Vp8 encoding loop supporting encoding multiple streams at a time.
- * Each output stream is described by encodingParams parameters allowing
- * simultaneous encoding of various resolutions, bitrates with an option to
- * control key frame and dynamic bitrate for each output stream indepandently.
- *
- * MediaCodec will raise an IllegalStateException
- * whenever vp8 encoder fails to encode a frame.
- *
- * Color format of input file should be YUV420, and frameWidth,
- * frameHeight should be supplied correctly as raw input file doesn't
- * include any header data.
- *
- * @param srcFrameWidth Frame width of input yuv file
- * @param srcFrameHeight Frame height of input yuv file
- * @param encodingParams Encoder parameters
- * @return Returns 2D array of encoded frames information for each stream and
- * for each frame.
- */
- protected ArrayList<ArrayList<MediaCodec.BufferInfo>> encodeSimulcast(
- int srcFrameWidth,
- int srcFrameHeight,
- ArrayList<EncoderOutputStreamParameters> encodingParams) throws Exception {
- int numEncoders = encodingParams.size();
-
- // Create arrays of input/output, formats, bitrates etc
- ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos =
- new ArrayList<ArrayList<MediaCodec.BufferInfo>>(numEncoders);
- InputStream yuvStream[] = new InputStream[numEncoders];
- IvfWriter[] ivf = new IvfWriter[numEncoders];
- FileOutputStream[] yuvScaled = new FileOutputStream[numEncoders];
- MediaFormat[] format = new MediaFormat[numEncoders];
- MediaEncoderAsync[] codec = new MediaEncoderAsync[numEncoders];
- int[] inputFrameIndex = new int[numEncoders];
- boolean[] sawInputEOS = new boolean[numEncoders];
- boolean[] consumedInputEOS = new boolean[numEncoders];
- boolean[] inputConsumed = new boolean[numEncoders];
- boolean[] bufferConsumed = new boolean[numEncoders];
- boolean[] sawOutputEOS = new boolean[numEncoders];
- byte[][] srcFrame = new byte[numEncoders][];
- boolean sawOutputEOSTotal = false;
- boolean bufferConsumedTotal = false;
- CodecProperties[] codecProperties = new CodecProperties[numEncoders];
-
- numEncoders = 0;
- for (EncoderOutputStreamParameters params : encodingParams) {
- int i = numEncoders;
- Log.d(TAG, "Source resolution: " + params.frameWidth + " x " +
- params.frameHeight);
- int bitrate = params.bitrateSet[0];
-
- // Create minimal media format signifying desired output.
- format[i] = MediaFormat.createVideoFormat(VP8_MIME,
- params.frameWidth, params.frameHeight);
- format[i].setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
- CodecProperties properties = getVpxCodecProperties(
- true, format[i], params.forceGoogleEncoder);
- if (properties == null) {
- continue;
- }
-
- // Check if scaled image was created
- int scale = params.frameWidth / srcFrameWidth;
- if (!mScaledImages.contains(scale)) {
- // resize image
- cacheScaledImage(params.inputYuvFilename, params.inputResourceId,
- srcFrameWidth, srcFrameHeight,
- params.scaledYuvFilename, params.frameWidth, params.frameHeight);
- mScaledImages.add(scale);
- }
-
- // Create buffer info storage
- bufferInfos.add(new ArrayList<MediaCodec.BufferInfo>());
-
- // Create YUV reader
- yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
-
- // Create IVF writer
- ivf[i] = new IvfWriter(params.outputIvfFilename, params.frameWidth, params.frameHeight);
-
- // Frame buffer
- int frameSize = params.frameWidth * params.frameHeight * 3 / 2;
- srcFrame[i] = new byte[frameSize];
-
- // Create a media format signifying desired output.
- if (params.bitrateType == VIDEO_ControlRateConstant) {
- format[i].setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
- }
- if (params.temporalLayers > 0) {
- format[i].setInteger("ts-layers", params.temporalLayers); // 1 temporal layer
- }
- format[i].setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
- format[i].setInteger(MediaFormat.KEY_FRAME_RATE, params.frameRate);
- int syncFrameInterval = (params.syncFrameInterval + params.frameRate/2) /
- params.frameRate; // in sec
- format[i].setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
- // Create encoder
- Log.d(TAG, "Creating encoder #" + i +" : " + properties.codecName +
- ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
- params.frameWidth + " x " + params.frameHeight +
- ". Bitrate: " + bitrate + " Bitrate type: " + params.bitrateType +
- ". Fps:" + params.frameRate + ". TS Layers: " + params.temporalLayers +
- ". Key frame:" + syncFrameInterval * params.frameRate +
- ". Force keyFrame: " + params.syncForceFrameInterval);
- Log.d(TAG, " Format: " + format[i]);
- Log.d(TAG, " Output ivf:" + params.outputIvfFilename);
-
- // Create encoder
- codec[i] = new MediaEncoderAsync();
- codec[i].createCodec(i, properties.codecName, format[i],
- params.timeoutDequeue, params.runInLooperThread);
- codecProperties[i] = new CodecProperties(properties.codecName, properties.colorFormat);
-
- inputConsumed[i] = true;
- ++numEncoders;
- }
- if (numEncoders == 0) {
- Log.i(TAG, "no suitable encoders found for any of the streams");
- return null;
- }
-
- while (!sawOutputEOSTotal) {
- // Feed input buffer to all encoders
- for (int i = 0; i < numEncoders; i++) {
- bufferConsumed[i] = false;
- if (consumedInputEOS[i]) {
- continue;
- }
-
- EncoderOutputStreamParameters params = encodingParams.get(i);
- // Read new input buffers - if previous input was consumed and no EOS
- if (inputConsumed[i] && !sawInputEOS[i]) {
- int bytesRead = yuvStream[i].read(srcFrame[i]);
-
- // Check EOS
- if (params.frameCount > 0 && inputFrameIndex[i] >= params.frameCount) {
- sawInputEOS[i] = true;
- Log.d(TAG, "---Enc" + i +
- ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
- }
-
- if (!sawInputEOS[i] && bytesRead == -1) {
- if (params.frameCount == 0) {
- sawInputEOS[i] = true;
- Log.d(TAG, "---Enc" + i +
- ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
- } else {
- yuvStream[i].close();
- yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
- bytesRead = yuvStream[i].read(srcFrame[i]);
- }
- }
-
- // Convert YUV420 to NV12 if necessary
- if (codecProperties[i].colorFormat !=
- CodecCapabilities.COLOR_FormatYUV420Planar) {
- srcFrame[i] =
- YUV420ToNV(params.frameWidth, params.frameHeight, srcFrame[i]);
- }
- }
-
- inputConsumed[i] = codec[i].feedInput(srcFrame[i], sawInputEOS[i]);
- if (inputConsumed[i]) {
- inputFrameIndex[i]++;
- consumedInputEOS[i] = sawInputEOS[i];
- bufferConsumed[i] = true;
- }
-
- }
-
- // Get output from all encoders
- for (int i = 0; i < numEncoders; i++) {
- if (sawOutputEOS[i]) {
- continue;
- }
-
- MediaEncoderOutput out = codec[i].getOutput();
- if (out.outputGenerated) {
- bufferConsumed[i] = true;
- // Detect output EOS
- if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- Log.d(TAG, "----Enc" + i + ". Output EOS ");
- sawOutputEOS[i] = true;
- }
-
- if (out.buffer.length > 0) {
- // Save frame
- ivf[i].writeFrame(out.buffer, out.outPresentationTimeUs);
-
- // Update statistics - store presentation time delay in offset
- long presentationTimeUsDelta = out.inPresentationTimeUs -
- out.outPresentationTimeUs;
- MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
- bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
- out.outPresentationTimeUs, out.flags);
- bufferInfos.get(i).add(bufferInfoCopy);
- }
- }
- }
-
- // If codec is not ready to accept input/output - wait for buffer ready callback
- bufferConsumedTotal = false;
- for (boolean bufferConsumedCurrent : bufferConsumed) {
- bufferConsumedTotal |= bufferConsumedCurrent;
- }
- if (!bufferConsumedTotal) {
- // Pick the encoder to wait for
- for (int i = 0; i < numEncoders; i++) {
- if (!bufferConsumed[i] && !sawOutputEOS[i]) {
- codec[i].waitForBufferEvent();
- break;
- }
- }
- }
-
- // Check if EOS happened for all encoders
- sawOutputEOSTotal = true;
- for (boolean sawOutputEOSStream : sawOutputEOS) {
- sawOutputEOSTotal &= sawOutputEOSStream;
- }
- }
-
- for (int i = 0; i < numEncoders; i++) {
- codec[i].deleteCodec();
- ivf[i].close();
- yuvStream[i].close();
- if (yuvScaled[i] != null) {
- yuvScaled[i].close();
- }
- }
-
- return bufferInfos;
- }
-
- /**
- * Some encoding statistics.
- */
- protected class Vp8EncodingStatistics {
- Vp8EncodingStatistics() {
- mBitrates = new ArrayList<Integer>();
- mFrames = new ArrayList<Integer>();
- mKeyFrames = new ArrayList<Integer>();
- mMinimumKeyFrameInterval = Integer.MAX_VALUE;
- }
-
- public ArrayList<Integer> mBitrates;// Bitrate values for each second of the encoded stream.
- public ArrayList<Integer> mFrames; // Number of frames in each second of the encoded stream.
- public int mAverageBitrate; // Average stream bitrate.
- public ArrayList<Integer> mKeyFrames;// Stores the position of key frames in a stream.
- public int mAverageKeyFrameInterval; // Average key frame interval.
- public int mMaximumKeyFrameInterval; // Maximum key frame interval.
- public int mMinimumKeyFrameInterval; // Minimum key frame interval.
- }
-
- /**
- * Calculates average bitrate and key frame interval for the encoded streams.
- * Output mBitrates field will contain bitrate values for every second
- * of the encoded stream.
- * Average stream bitrate will be stored in mAverageBitrate field.
- * mKeyFrames array will contain the position of key frames in the encoded stream and
- * mKeyFrameInterval - average key frame interval.
- */
- protected Vp8EncodingStatistics computeEncodingStatistics(int encoderId,
- ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
- Vp8EncodingStatistics statistics = new Vp8EncodingStatistics();
-
- int totalSize = 0;
- int frames = 0;
- int framesPerSecond = 0;
- int totalFrameSizePerSecond = 0;
- int maxFrameSize = 0;
- int currentSecond;
- int nextSecond = 0;
- String keyFrameList = " IFrame List: ";
- String bitrateList = " Bitrate list: ";
- String framesList = " FPS list: ";
-
-
- for (int j = 0; j < bufferInfos.size(); j++) {
- MediaCodec.BufferInfo info = bufferInfos.get(j);
- currentSecond = (int)(info.presentationTimeUs / 1000000);
- boolean lastFrame = (j == bufferInfos.size() - 1);
- if (!lastFrame) {
- nextSecond = (int)(bufferInfos.get(j+1).presentationTimeUs / 1000000);
- }
-
- totalSize += info.size;
- totalFrameSizePerSecond += info.size;
- maxFrameSize = Math.max(maxFrameSize, info.size);
- framesPerSecond++;
- frames++;
-
- // Update the bitrate statistics if the next frame will
- // be for the next second
- if (lastFrame || nextSecond > currentSecond) {
- int currentBitrate = totalFrameSizePerSecond * 8;
- bitrateList += (currentBitrate + " ");
- framesList += (framesPerSecond + " ");
- statistics.mBitrates.add(currentBitrate);
- statistics.mFrames.add(framesPerSecond);
- totalFrameSizePerSecond = 0;
- framesPerSecond = 0;
- }
-
- // Update key frame statistics.
- if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
- statistics.mKeyFrames.add(j);
- keyFrameList += (j + " ");
- }
- }
- int duration = (int)(bufferInfos.get(bufferInfos.size() - 1).presentationTimeUs / 1000);
- duration = (duration + 500) / 1000;
- statistics.mAverageBitrate = (int)(((long)totalSize * 8) / duration);
- Log.d(TAG, "Statistics for encoder # " + encoderId);
- // Calculate average key frame interval in frames.
- int keyFrames = statistics.mKeyFrames.size();
- if (keyFrames > 1) {
- statistics.mAverageKeyFrameInterval =
- statistics.mKeyFrames.get(keyFrames - 1) - statistics.mKeyFrames.get(0);
- statistics.mAverageKeyFrameInterval =
- Math.round((float)statistics.mAverageKeyFrameInterval / (keyFrames - 1));
- for (int j = 1; j < keyFrames; j++) {
- int keyFrameInterval =
- statistics.mKeyFrames.get(j) - statistics.mKeyFrames.get(j - 1);
- statistics.mMaximumKeyFrameInterval =
- Math.max(statistics.mMaximumKeyFrameInterval, keyFrameInterval);
- statistics.mMinimumKeyFrameInterval =
- Math.min(statistics.mMinimumKeyFrameInterval, keyFrameInterval);
- }
- Log.d(TAG, " Key frame intervals: Max: " + statistics.mMaximumKeyFrameInterval +
- ". Min: " + statistics.mMinimumKeyFrameInterval +
- ". Avg: " + statistics.mAverageKeyFrameInterval);
- }
- Log.d(TAG, " Frames: " + frames + ". Duration: " + duration +
- ". Total size: " + totalSize + ". Key frames: " + keyFrames);
- Log.d(TAG, keyFrameList);
- Log.d(TAG, bitrateList);
- Log.d(TAG, framesList);
- Log.d(TAG, " Bitrate average: " + statistics.mAverageBitrate);
- Log.d(TAG, " Maximum frame size: " + maxFrameSize);
-
- return statistics;
- }
-
- protected Vp8EncodingStatistics computeEncodingStatistics(
- ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
- return computeEncodingStatistics(0, bufferInfos);
- }
-
- protected ArrayList<Vp8EncodingStatistics> computeSimulcastEncodingStatistics(
- ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos) {
- int numCodecs = bufferInfos.size();
- ArrayList<Vp8EncodingStatistics> statistics = new ArrayList<Vp8EncodingStatistics>();
-
- for (int i = 0; i < numCodecs; i++) {
- Vp8EncodingStatistics currentStatistics =
- computeEncodingStatistics(i, bufferInfos.get(i));
- statistics.add(currentStatistics);
- }
- return statistics;
- }
-
- /**
- * Calculates maximum latency for encoder/decoder based on buffer info array
- * generated either by encoder or decoder.
- */
- protected int maxPresentationTimeDifference(ArrayList<MediaCodec.BufferInfo> bufferInfos) {
- int maxValue = 0;
- for (MediaCodec.BufferInfo bufferInfo : bufferInfos) {
- maxValue = Math.max(maxValue, bufferInfo.offset);
- }
- maxValue = (maxValue + 500) / 1000; // mcs -> ms
- return maxValue;
- }
-
- /**
- * Decoding PSNR statistics.
- */
- protected class Vp8DecodingStatistics {
- Vp8DecodingStatistics() {
- mMinimumPSNR = Integer.MAX_VALUE;
- }
- public double mAveragePSNR;
- public double mMinimumPSNR;
- }
-
- /**
- * Calculates PSNR value between two video frames.
- */
- private double computePSNR(byte[] data0, byte[] data1) {
- long squareError = 0;
- assertTrue(data0.length == data1.length);
- int length = data0.length;
- for (int i = 0 ; i < length; i++) {
- int diff = ((int)data0[i] & 0xff) - ((int)data1[i] & 0xff);
- squareError += diff * diff;
- }
- double meanSquareError = (double)squareError / length;
- double psnr = 10 * Math.log10((double)255 * 255 / meanSquareError);
- return psnr;
- }
-
- /**
- * Calculates average and minimum PSNR values between
- * set of reference and decoded video frames.
- * Runs PSNR calculation for the full duration of the decoded data.
- */
- protected Vp8DecodingStatistics computeDecodingStatistics(
- String referenceYuvFilename,
- int referenceYuvRawId,
- String decodedYuvFilename,
- int width,
- int height) throws Exception {
- Vp8DecodingStatistics statistics = new Vp8DecodingStatistics();
- InputStream referenceStream =
- OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
- InputStream decodedStream = new FileInputStream(decodedYuvFilename);
-
- int ySize = width * height;
- int uvSize = width * height / 4;
- byte[] yRef = new byte[ySize];
- byte[] yDec = new byte[ySize];
- byte[] uvRef = new byte[uvSize];
- byte[] uvDec = new byte[uvSize];
-
- int frames = 0;
- double averageYPSNR = 0;
- double averageUPSNR = 0;
- double averageVPSNR = 0;
- double minimumYPSNR = Integer.MAX_VALUE;
- double minimumUPSNR = Integer.MAX_VALUE;
- double minimumVPSNR = Integer.MAX_VALUE;
- int minimumPSNRFrameIndex = 0;
-
- while (true) {
- // Calculate Y PSNR.
- int bytesReadRef = referenceStream.read(yRef);
- int bytesReadDec = decodedStream.read(yDec);
- if (bytesReadDec == -1) {
- break;
- }
- if (bytesReadRef == -1) {
- // Reference file wrapping up
- referenceStream.close();
- referenceStream =
- OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
- bytesReadRef = referenceStream.read(yRef);
- }
- double curYPSNR = computePSNR(yRef, yDec);
- averageYPSNR += curYPSNR;
- minimumYPSNR = Math.min(minimumYPSNR, curYPSNR);
- double curMinimumPSNR = curYPSNR;
-
- // Calculate U PSNR.
- bytesReadRef = referenceStream.read(uvRef);
- bytesReadDec = decodedStream.read(uvDec);
- double curUPSNR = computePSNR(uvRef, uvDec);
- averageUPSNR += curUPSNR;
- minimumUPSNR = Math.min(minimumUPSNR, curUPSNR);
- curMinimumPSNR = Math.min(curMinimumPSNR, curUPSNR);
-
- // Calculate V PSNR.
- bytesReadRef = referenceStream.read(uvRef);
- bytesReadDec = decodedStream.read(uvDec);
- double curVPSNR = computePSNR(uvRef, uvDec);
- averageVPSNR += curVPSNR;
- minimumVPSNR = Math.min(minimumVPSNR, curVPSNR);
- curMinimumPSNR = Math.min(curMinimumPSNR, curVPSNR);
-
- // Frame index for minimum PSNR value - help to detect possible distortions
- if (curMinimumPSNR < statistics.mMinimumPSNR) {
- statistics.mMinimumPSNR = curMinimumPSNR;
- minimumPSNRFrameIndex = frames;
- }
-
- String logStr = String.format(Locale.US, "PSNR #%d: Y: %.2f. U: %.2f. V: %.2f",
- frames, curYPSNR, curUPSNR, curVPSNR);
- Log.v(TAG, logStr);
-
- frames++;
- }
-
- averageYPSNR /= frames;
- averageUPSNR /= frames;
- averageVPSNR /= frames;
- statistics.mAveragePSNR = (4 * averageYPSNR + averageUPSNR + averageVPSNR) / 6;
-
- Log.d(TAG, "PSNR statistics for " + frames + " frames.");
- String logStr = String.format(Locale.US,
- "Average PSNR: Y: %.1f. U: %.1f. V: %.1f. Average: %.1f",
- averageYPSNR, averageUPSNR, averageVPSNR, statistics.mAveragePSNR);
- Log.d(TAG, logStr);
- logStr = String.format(Locale.US,
- "Minimum PSNR: Y: %.1f. U: %.1f. V: %.1f. Overall: %.1f at frame %d",
- minimumYPSNR, minimumUPSNR, minimumVPSNR,
- statistics.mMinimumPSNR, minimumPSNRFrameIndex);
- Log.d(TAG, logStr);
-
- referenceStream.close();
- decodedStream.close();
- return statistics;
- }
-}
-
diff --git a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
deleted file mode 100644
index 5552f6c..0000000
--- a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.cts;
-
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
-import android.media.MediaFormat;
-import android.util.Log;
-import android.media.cts.R;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Verification test for vp8 encoder and decoder.
- *
- * A raw yv12 stream is encoded at various settings and written to an IVF
- * file. Encoded stream bitrate and key frame interval are checked against target values.
- * The stream is later decoded by vp8 decoder to verify frames are decodable and to
- * calculate PSNR values for various bitrates.
- */
-public class Vp8EncoderTest extends Vp8CodecTestBase {
-
- private static final String ENCODED_IVF_BASE = "football";
- private static final String INPUT_YUV = null;
- private static final String OUTPUT_YUV = SDCARD_DIR + File.separator +
- ENCODED_IVF_BASE + "_out.yuv";
-
- // YUV stream properties.
- private static final int WIDTH = 320;
- private static final int HEIGHT = 240;
- private static final int FPS = 30;
- // Default encoding bitrate.
- private static final int BITRATE = 400000;
- // Default encoding bitrate mode
- private static final int BITRATE_MODE = VIDEO_ControlRateVariable;
- // List of bitrates used in quality and basic bitrate tests.
- private static final int[] TEST_BITRATES_SET = { 300000, 500000, 700000, 900000 };
- // Maximum allowed bitrate variation from the target value.
- private static final double MAX_BITRATE_VARIATION = 0.2;
- // Average PSNR values for reference Google VP8 codec for the above bitrates.
- private static final double[] REFERENCE_AVERAGE_PSNR = { 33.1, 35.2, 36.6, 37.8 };
- // Minimum PSNR values for reference Google VP8 codec for the above bitrates.
- private static final double[] REFERENCE_MINIMUM_PSNR = { 25.9, 27.5, 28.4, 30.3 };
- // Maximum allowed average PSNR difference of encoder comparing to reference Google encoder.
- private static final double MAX_AVERAGE_PSNR_DIFFERENCE = 2;
- // Maximum allowed minimum PSNR difference of encoder comparing to reference Google encoder.
- private static final double MAX_MINIMUM_PSNR_DIFFERENCE = 4;
- // Maximum allowed average PSNR difference of the encoder running in a looper thread with 0 ms
- // buffer dequeue timeout comparing to the encoder running in a callee's thread with 100 ms
- // buffer dequeue timeout.
- private static final double MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE = 0.5;
- // Maximum allowed minimum PSNR difference of the encoder running in a looper thread
- // comparing to the encoder running in a callee's thread.
- private static final double MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE = 2;
- // Maximum allowed average key frame interval variation from the target value.
- private static final int MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION = 1;
- // Maximum allowed key frame interval variation from the target value.
- private static final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
-
- /**
- * A basic test for VP8 encoder.
- *
- * Encodes 9 seconds of raw stream with default configuration options,
- * and then decodes it to verify the bitstream.
- * Also checks the average bitrate is within MAX_BITRATE_VARIATION of the target value.
- */
- public void testBasic() throws Exception {
- int encodeSeconds = 9;
- boolean skipped = true;
-
- for (int targetBitrate : TEST_BITRATES_SET) {
- EncoderOutputStreamParameters params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- BITRATE_MODE,
- targetBitrate,
- true);
- ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
- if (bufInfo == null) {
- continue;
- }
- skipped = false;
-
- Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
-
- assertEquals("Stream bitrate " + statistics.mAverageBitrate +
- " is different from the target " + targetBitrate,
- targetBitrate, statistics.mAverageBitrate,
- MAX_BITRATE_VARIATION * targetBitrate);
-
- decode(params.outputIvfFilename, null, FPS, params.forceGoogleEncoder);
- }
-
- if (skipped) {
- Log.i(TAG, "SKIPPING testBasic(): codec is not supported");
- }
- }
-
- /**
- * Asynchronous encoding test for VP8 encoder.
- *
- * Encodes 9 seconds of raw stream using synchronous and asynchronous calls.
- * Checks the PSNR difference between the encoded and decoded output and reference yuv input
- * does not change much for two different ways of the encoder call.
- */
- public void testAsyncEncoding() throws Exception {
- int encodeSeconds = 9;
-
- // First test the encoder running in a looper thread with buffer callbacks enabled.
- boolean syncEncoding = false;
- EncoderOutputStreamParameters params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- BITRATE_MODE,
- BITRATE,
- syncEncoding);
- ArrayList<MediaCodec.BufferInfo> bufInfos = encodeAsync(params);
- if (bufInfos == null) {
- Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
- return;
- }
- computeEncodingStatistics(bufInfos);
- decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
- Vp8DecodingStatistics statisticsAsync = computeDecodingStatistics(
- params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
- params.frameWidth, params.frameHeight);
-
-
- // Test the encoder running in a callee's thread.
- syncEncoding = true;
- params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- BITRATE_MODE,
- BITRATE,
- syncEncoding);
- bufInfos = encode(params);
- if (bufInfos == null) {
- Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
- return;
- }
- computeEncodingStatistics(bufInfos);
- decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
- Vp8DecodingStatistics statisticsSync = computeDecodingStatistics(
- params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
- params.frameWidth, params.frameHeight);
-
- // Check PSNR difference.
- Log.d(TAG, "PSNR Average: Async: " + statisticsAsync.mAveragePSNR +
- ". Sync: " + statisticsSync.mAveragePSNR);
- Log.d(TAG, "PSNR Minimum: Async: " + statisticsAsync.mMinimumPSNR +
- ". Sync: " + statisticsSync.mMinimumPSNR);
- if ((Math.abs(statisticsAsync.mAveragePSNR - statisticsSync.mAveragePSNR) >
- MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE) ||
- (Math.abs(statisticsAsync.mMinimumPSNR - statisticsSync.mMinimumPSNR) >
- MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE)) {
- throw new RuntimeException("Difference between PSNRs for async and sync encoders");
- }
- }
-
- /**
- * Check if MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME is honored.
- *
- * Encodes 9 seconds of raw stream and requests a sync frame every second (30 frames).
- * The test does not verify the output stream.
- */
- public void testSyncFrame() throws Exception {
- int encodeSeconds = 9;
-
- EncoderOutputStreamParameters params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- BITRATE_MODE,
- BITRATE,
- true);
- params.syncFrameInterval = encodeSeconds * FPS;
- params.syncForceFrameInterval = FPS;
- ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
- if (bufInfo == null) {
- Log.i(TAG, "SKIPPING testSyncFrame(): no suitable encoder found");
- return;
- }
-
- Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
-
- // First check if we got expected number of key frames.
- int actualKeyFrames = statistics.mKeyFrames.size();
- if (actualKeyFrames != encodeSeconds) {
- throw new RuntimeException("Number of key frames " + actualKeyFrames +
- " is different from the expected " + encodeSeconds);
- }
-
- // Check key frame intervals:
- // Average value should be within +/- 1 frame of the target value,
- // maximum value should not be greater than target value + 3,
- // and minimum value should not be less that target value - 3.
- if (Math.abs(statistics.mAverageKeyFrameInterval - FPS) >
- MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION ||
- (statistics.mMaximumKeyFrameInterval - FPS > MAX_KEYFRAME_INTERVAL_VARIATION) ||
- (FPS - statistics.mMinimumKeyFrameInterval > MAX_KEYFRAME_INTERVAL_VARIATION)) {
- throw new RuntimeException(
- "Key frame intervals are different from the expected " + FPS);
- }
- }
-
- /**
- * Check if MediaCodec.PARAMETER_KEY_VIDEO_BITRATE is honored.
- *
- * Run the the encoder for 12 seconds. Request changes to the
- * bitrate after 6 seconds and ensure the encoder responds.
- */
- public void testDynamicBitrateChange() throws Exception {
- int encodeSeconds = 12; // Encoding sequence duration in seconds.
- int[] bitrateTargetValues = { 400000, 800000 }; // List of bitrates to test.
-
- EncoderOutputStreamParameters params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- BITRATE_MODE,
- bitrateTargetValues[0],
- true);
-
- // Number of seconds for each bitrate
- int stepSeconds = encodeSeconds / bitrateTargetValues.length;
- // Fill the bitrates values.
- params.bitrateSet = new int[encodeSeconds * FPS];
- for (int i = 0; i < bitrateTargetValues.length ; i++) {
- Arrays.fill(params.bitrateSet,
- i * encodeSeconds * FPS / bitrateTargetValues.length,
- (i + 1) * encodeSeconds * FPS / bitrateTargetValues.length,
- bitrateTargetValues[i]);
- }
-
- ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
- if (bufInfo == null) {
- Log.i(TAG, "SKIPPING testDynamicBitrateChange(): no suitable encoder found");
- return;
- }
-
- Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
-
- // Calculate actual average bitrates for every [stepSeconds] second.
- int[] bitrateActualValues = new int[bitrateTargetValues.length];
- for (int i = 0; i < bitrateTargetValues.length ; i++) {
- bitrateActualValues[i] = 0;
- for (int j = i * stepSeconds; j < (i + 1) * stepSeconds; j++) {
- bitrateActualValues[i] += statistics.mBitrates.get(j);
- }
- bitrateActualValues[i] /= stepSeconds;
- Log.d(TAG, "Actual bitrate for interval #" + i + " : " + bitrateActualValues[i] +
- ". Target: " + bitrateTargetValues[i]);
-
- // Compare actual bitrate values to make sure at least same increasing/decreasing
- // order as the target bitrate values.
- for (int j = 0; j < i; j++) {
- long differenceTarget = bitrateTargetValues[i] - bitrateTargetValues[j];
- long differenceActual = bitrateActualValues[i] - bitrateActualValues[j];
- if (differenceTarget * differenceActual < 0) {
- throw new RuntimeException("Target bitrates: " +
- bitrateTargetValues[j] + " , " + bitrateTargetValues[i] +
- ". Actual bitrates: "
- + bitrateActualValues[j] + " , " + bitrateActualValues[i]);
- }
- }
- }
- }
-
- /**
- * Check if encoder and decoder can run simultaneously on different threads.
- *
- * Encodes and decodes 9 seconds of raw stream sequentially in CBR mode,
- * and then run parallel encoding and decoding of the same streams.
- * Compares average bitrate and PSNR for sequential and parallel runs.
- */
- public void testParallelEncodingAndDecoding() throws Exception {
- // check for encoder up front, as by the time we detect lack of
- // encoder support, we may have already started decoding.
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- MediaFormat format = MediaFormat.createVideoFormat(VP8_MIME, WIDTH, HEIGHT);
- if (mcl.findEncoderForFormat(format) == null) {
- Log.i(TAG, "SKIPPING testParallelEncodingAndDecoding(): no suitable encoder found");
- return;
- }
-
- int encodeSeconds = 9;
- final int[] bitrate = new int[1];
- final double[] psnr = new double[1];
- final Exception[] exceptionEncoder = new Exception[1];
- final Exception[] exceptionDecoder = new Exception[1];
- final EncoderOutputStreamParameters params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- VIDEO_ControlRateConstant,
- BITRATE,
- true);
- final String inputIvfFilename = params.outputIvfFilename;
-
- Runnable runEncoder = new Runnable() {
- public void run() {
- try {
- ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
- Vp8EncodingStatistics statistics = computeEncodingStatistics(bufInfo);
- bitrate[0] = statistics.mAverageBitrate;
- } catch (Exception e) {
- Log.e(TAG, "Encoder error: " + e.toString());
- exceptionEncoder[0] = e;
- }
- }
- };
- Runnable runDecoder = new Runnable() {
- public void run() {
- try {
- decode(inputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
- Vp8DecodingStatistics statistics = computeDecodingStatistics(
- params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
- params.frameWidth, params.frameHeight);
- psnr[0] = statistics.mAveragePSNR;
- } catch (Exception e) {
- Log.e(TAG, "Decoder error: " + e.toString());
- exceptionDecoder[0] = e;
- }
- }
- };
-
- // Sequential encoding and decoding.
- runEncoder.run();
- if (exceptionEncoder[0] != null) {
- throw exceptionEncoder[0];
- }
- int referenceBitrate = bitrate[0];
- runDecoder.run();
- if (exceptionDecoder[0] != null) {
- throw exceptionDecoder[0];
- }
- double referencePsnr = psnr[0];
-
- // Parallel encoding and decoding.
- params.outputIvfFilename = SDCARD_DIR + File.separator + ENCODED_IVF_BASE + "_copy.ivf";
- Thread threadEncoder = new Thread(runEncoder);
- Thread threadDecoder = new Thread(runDecoder);
- threadEncoder.start();
- threadDecoder.start();
- threadEncoder.join();
- threadDecoder.join();
- if (exceptionEncoder[0] != null) {
- throw exceptionEncoder[0];
- }
- if (exceptionDecoder[0] != null) {
- throw exceptionDecoder[0];
- }
-
- // Compare bitrates and PSNRs for sequential and parallel cases.
- Log.d(TAG, "Sequential bitrate: " + referenceBitrate + ". PSNR: " + referencePsnr);
- Log.d(TAG, "Parallel bitrate: " + bitrate[0] + ". PSNR: " + psnr[0]);
- assertEquals("Bitrate for sequenatial encoding" + referenceBitrate +
- " is different from parallel encoding " + bitrate[0],
- referenceBitrate, bitrate[0], MAX_BITRATE_VARIATION * referenceBitrate);
- assertEquals("PSNR for sequenatial encoding" + referencePsnr +
- " is different from parallel encoding " + psnr[0],
- referencePsnr, psnr[0], MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE);
- }
-
-
- /**
- * Check the encoder quality for various bitrates by calculating PSNR
- *
- * Run the the encoder for 9 seconds for each bitrate and calculate PSNR
- * for each encoded stream.
- * Video streams with higher bitrates should have higher PSNRs.
- * Also compares average and minimum PSNR of codec with PSNR values of reference Google codec.
- */
- public void testEncoderQuality() throws Exception {
- int encodeSeconds = 9; // Encoding sequence duration in seconds for each bitrate.
- double[] psnrPlatformCodecAverage = new double[TEST_BITRATES_SET.length];
- double[] psnrPlatformCodecMin = new double[TEST_BITRATES_SET.length];
- boolean[] completed = new boolean[TEST_BITRATES_SET.length];
- boolean skipped = true;
-
- // Run platform specific encoder for different bitrates
- // and compare PSNR of codec with PSNR of reference Google codec.
- for (int i = 0; i < TEST_BITRATES_SET.length; i++) {
- EncoderOutputStreamParameters params = getDefaultEncodingParameters(
- INPUT_YUV,
- ENCODED_IVF_BASE,
- encodeSeconds,
- WIDTH,
- HEIGHT,
- FPS,
- BITRATE_MODE,
- TEST_BITRATES_SET[i],
- true);
- if (encode(params) == null) {
- // parameters not supported, try other bitrates
- completed[i] = false;
- continue;
- }
- completed[i] = true;
- skipped = false;
-
- decode(params.outputIvfFilename, OUTPUT_YUV, FPS, params.forceGoogleEncoder);
- Vp8DecodingStatistics statistics = computeDecodingStatistics(
- params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
- params.frameWidth, params.frameHeight);
- psnrPlatformCodecAverage[i] = statistics.mAveragePSNR;
- psnrPlatformCodecMin[i] = statistics.mMinimumPSNR;
- }
-
- if (skipped) {
- Log.i(TAG, "SKIPPING testEncoderQuality(): no bitrates supported");
- return;
- }
-
- // First do a sanity check - higher bitrates should results in higher PSNR.
- for (int i = 1; i < TEST_BITRATES_SET.length ; i++) {
- if (!completed[i]) {
- continue;
- }
- for (int j = 0; j < i; j++) {
- if (!completed[j]) {
- continue;
- }
- double differenceBitrate = TEST_BITRATES_SET[i] - TEST_BITRATES_SET[j];
- double differencePSNR = psnrPlatformCodecAverage[i] - psnrPlatformCodecAverage[j];
- if (differenceBitrate * differencePSNR < 0) {
- throw new RuntimeException("Target bitrates: " +
- TEST_BITRATES_SET[j] + ", " + TEST_BITRATES_SET[i] +
- ". Actual PSNRs: "
- + psnrPlatformCodecAverage[j] + ", " + psnrPlatformCodecAverage[i]);
- }
- }
- }
-
- // Then compare average and minimum PSNR of platform codec with reference Google codec -
- // average PSNR for platform codec should be no more than 2 dB less than reference PSNR
- // and minumum PSNR - no more than 4 dB less than reference minimum PSNR.
- // These PSNR difference numbers are arbitrary for now, will need further estimation
- // when more devices with HW VP8 codec will appear.
- for (int i = 0; i < TEST_BITRATES_SET.length ; i++) {
- if (!completed[i]) {
- continue;
- }
-
- Log.d(TAG, "Bitrate " + TEST_BITRATES_SET[i]);
- Log.d(TAG, "Reference: Average: " + REFERENCE_AVERAGE_PSNR[i] + ". Minimum: " +
- REFERENCE_MINIMUM_PSNR[i]);
- Log.d(TAG, "Platform: Average: " + psnrPlatformCodecAverage[i] + ". Minimum: " +
- psnrPlatformCodecMin[i]);
- if (psnrPlatformCodecAverage[i] < REFERENCE_AVERAGE_PSNR[i] -
- MAX_AVERAGE_PSNR_DIFFERENCE) {
- throw new RuntimeException("Low average PSNR " + psnrPlatformCodecAverage[i] +
- " comparing to reference PSNR " + REFERENCE_AVERAGE_PSNR[i] +
- " for bitrate " + TEST_BITRATES_SET[i]);
- }
- if (psnrPlatformCodecMin[i] < REFERENCE_MINIMUM_PSNR[i] -
- MAX_MINIMUM_PSNR_DIFFERENCE) {
- throw new RuntimeException("Low minimum PSNR " + psnrPlatformCodecMin[i] +
- " comparing to reference PSNR " + REFERENCE_MINIMUM_PSNR[i] +
- " for bitrate " + TEST_BITRATES_SET[i]);
- }
- }
- }
-}
-
diff --git a/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java b/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
new file mode 100644
index 0000000..ea72225
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VpxCodecTestBase.java
@@ -0,0 +1,2016 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.media.MediaCodec;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Looper;
+import android.os.Handler;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.media.cts.R;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Verification test for vpx encoder and decoder.
+ *
+ * A raw yv12 stream is encoded at various settings and written to an IVF
+ * file. Encoded stream bitrate and key frame interval are checked against target values.
+ * The stream is later decoded by the decoder to verify frames are decodable and to
+ * calculate PSNR values for various bitrates.
+ */
+public class VpxCodecTestBase extends AndroidTestCase {
+
+ protected static final String TAG = "VPxCodecTestBase";
+ protected static final String VP8_MIME = MediaFormat.MIMETYPE_VIDEO_VP8;
+ protected static final String VP9_MIME = MediaFormat.MIMETYPE_VIDEO_VP9;
+ private static final String GOOGLE_CODEC_PREFIX = "omx.google.";
+ protected static final String SDCARD_DIR =
+ Environment.getExternalStorageDirectory().getAbsolutePath();
+
+ // Default timeout for MediaCodec buffer dequeue - 200 ms.
+ protected static final long DEFAULT_DEQUEUE_TIMEOUT_US = 200000;
+ // Default timeout for MediaEncoderAsync - 30 sec.
+ protected static final long DEFAULT_ENCODE_TIMEOUT_MS = 30000;
+ // Default sync frame interval in frames (zero means allow the encoder to auto-select
+ // key frame interval).
+ private static final int SYNC_FRAME_INTERVAL = 0;
+ // Video bitrate type - should be set to OMX_Video_ControlRateConstant from OMX_Video.h
+ protected static final int VIDEO_ControlRateVariable = 1;
+ protected static final int VIDEO_ControlRateConstant = 2;
+ // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
+ // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
+ private static final int COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
+ // Allowable color formats supported by codec - in order of preference.
+ private static final int[] mSupportedColorList = {
+ CodecCapabilities.COLOR_FormatYUV420Planar,
+ CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
+ CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
+ COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
+ };
+ // Scaled image cache list - contains scale factors, for which up-scaled frames
+ // were calculated and were written to yuv file.
+ ArrayList<Integer> mScaledImages = new ArrayList<Integer>();
+
+ private Resources mResources;
+
+ @Override
+ public void setContext(Context context) {
+ super.setContext(context);
+ mResources = mContext.getResources();
+ }
+
+ /**
+ * VPx codec properties generated by getVpxCodecProperties() function.
+ */
+ private class CodecProperties {
+ CodecProperties(String codecName, int colorFormat) {
+ this.codecName = codecName;
+ this.colorFormat = colorFormat;
+ }
+ public boolean isGoogleCodec() {
+ return codecName.toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
+ }
+
+ public final String codecName; // OpenMax component name for VPx codec.
+ public final int colorFormat; // Color format supported by codec.
+ }
+
+ /**
+ * Function to find VPx codec.
+ *
+ * Iterates through the list of available codecs and tries to find
+ * VPX codec, which can support either YUV420 planar or NV12 color formats.
+ * If forceGoogleCodec parameter set to true the function always returns
+ * Google VPX codec.
+ * If forceGoogleCodec parameter set to false the functions looks for platform
+ * specific VPX codec first. If no platform specific codec exist, falls back to
+ * Google VPX codec.
+ *
+ * @param isEncoder Flag if encoder is requested.
+ * @param forceGoogleCodec Forces to use Google codec.
+ */
+ private CodecProperties getVpxCodecProperties(
+ boolean isEncoder,
+ MediaFormat format,
+ boolean forceGoogleCodec) throws Exception {
+ CodecProperties codecProperties = null;
+ String mime = format.getString(MediaFormat.KEY_MIME);
+
+ // Loop through the list of omx components in case platform specific codec
+ // is requested.
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ for (MediaCodecInfo codecInfo : mcl.getCodecInfos()) {
+ if (isEncoder != codecInfo.isEncoder()) {
+ continue;
+ }
+ Log.v(TAG, codecInfo.getName());
+ // TODO: remove dependence of Google from the test
+ // Check if this is Google codec - we should ignore it.
+ boolean isGoogleCodec =
+ codecInfo.getName().toLowerCase().startsWith(GOOGLE_CODEC_PREFIX);
+ if (!isGoogleCodec && forceGoogleCodec) {
+ continue;
+ }
+
+ for (String type : codecInfo.getSupportedTypes()) {
+ if (!type.equalsIgnoreCase(mime)) {
+ continue;
+ }
+ CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(type);
+ if (!capabilities.isFormatSupported(format)) {
+ continue;
+ }
+
+ // Get candidate codec properties.
+ Log.v(TAG, "Found candidate codec " + codecInfo.getName());
+ for (int colorFormat: capabilities.colorFormats) {
+ Log.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat));
+ }
+
+ // Check supported color formats.
+ for (int supportedColorFormat : mSupportedColorList) {
+ for (int codecColorFormat : capabilities.colorFormats) {
+ if (codecColorFormat == supportedColorFormat) {
+ codecProperties = new CodecProperties(codecInfo.getName(),
+ codecColorFormat);
+ Log.v(TAG, "Found target codec " + codecProperties.codecName +
+ ". Color: 0x" + Integer.toHexString(codecColorFormat));
+ // return first HW codec found
+ if (!isGoogleCodec) {
+ return codecProperties;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (codecProperties == null) {
+ Log.i(TAG, "no suitable " + (forceGoogleCodec ? "google " : "")
+ + (isEncoder ? "encoder " : "decoder ") + "found for " + format);
+ }
+ return codecProperties;
+ }
+
+ /**
+ * Parameters for encoded video stream.
+ */
+ protected class EncoderOutputStreamParameters {
+ // Name of raw YUV420 input file. When the value of this parameter
+ // is set to null input file descriptor from inputResourceId parameter
+ // is used instead.
+ public String inputYuvFilename;
+ // Name of scaled YUV420 input file.
+ public String scaledYuvFilename;
+ // File descriptor for the raw input file (YUV420). Used only if
+ // inputYuvFilename parameter is null.
+ int inputResourceId;
+ // Name of the IVF file to write encoded bitsream
+ public String outputIvfFilename;
+ // Mime Type of the Encoded content.
+ public String codecMimeType;
+ // Force to use Google VPx encoder.
+ boolean forceGoogleEncoder;
+ // Number of frames to encode.
+ int frameCount;
+ // Frame rate of input file in frames per second.
+ int frameRate;
+ // Encoded frame width.
+ public int frameWidth;
+ // Encoded frame height.
+ public int frameHeight;
+ // Encoding bitrate array in bits/second for every frame. If array length
+ // is shorter than the total number of frames, the last value is re-used for
+ // all remaining frames. For constant bitrate encoding single element
+ // array can be used with first element set to target bitrate value.
+ public int[] bitrateSet;
+ // Encoding bitrate type - VBR or CBR
+ public int bitrateType;
+ // Number of temporal layers
+ public int temporalLayers;
+ // Desired key frame interval - codec is asked to generate key frames
+ // at a period defined by this parameter.
+ public int syncFrameInterval;
+ // Optional parameter - forced key frame interval. Used to
+ // explicitly request the codec to generate key frames using
+ // MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME parameter.
+ public int syncForceFrameInterval;
+ // Buffer timeout
+ long timeoutDequeue;
+ // Flag if encoder should run in Looper thread.
+ boolean runInLooperThread;
+ }
+
+ /**
+ * Generates an array of default parameters for encoder output stream based on
+ * upscaling value.
+ */
+ protected ArrayList<EncoderOutputStreamParameters> getDefaultEncodingParameterList(
+ String inputYuvName,
+ String outputIvfBaseName,
+ String codecMimeType,
+ int encodeSeconds,
+ int[] resolutionScales,
+ int frameWidth,
+ int frameHeight,
+ int frameRate,
+ int bitrateMode,
+ int[] bitrates,
+ boolean syncEncoding) {
+ assertTrue(resolutionScales.length == bitrates.length);
+ int numCodecs = resolutionScales.length;
+ ArrayList<EncoderOutputStreamParameters> outputParameters =
+ new ArrayList<EncoderOutputStreamParameters>(numCodecs);
+ for (int i = 0; i < numCodecs; i++) {
+ EncoderOutputStreamParameters params = new EncoderOutputStreamParameters();
+ if (inputYuvName != null) {
+ params.inputYuvFilename = SDCARD_DIR + File.separator + inputYuvName;
+ } else {
+ params.inputYuvFilename = null;
+ }
+ params.scaledYuvFilename = SDCARD_DIR + File.separator +
+ outputIvfBaseName + resolutionScales[i]+ ".yuv";
+ params.inputResourceId = R.raw.football_qvga;
+ params.codecMimeType = codecMimeType;
+ String codecSuffix = VP8_MIME.equals(codecMimeType) ? "vp8" : "vp9";
+ params.outputIvfFilename = SDCARD_DIR + File.separator +
+ outputIvfBaseName + resolutionScales[i] + "_" + codecSuffix + ".ivf";
+ params.forceGoogleEncoder = false;
+ params.frameCount = encodeSeconds * frameRate;
+ params.frameRate = frameRate;
+ params.frameWidth = Math.min(frameWidth * resolutionScales[i], 1280);
+ params.frameHeight = Math.min(frameHeight * resolutionScales[i], 720);
+ params.bitrateSet = new int[1];
+ params.bitrateSet[0] = bitrates[i];
+ params.bitrateType = bitrateMode;
+ params.temporalLayers = 0;
+ params.syncFrameInterval = SYNC_FRAME_INTERVAL;
+ params.syncForceFrameInterval = 0;
+ if (syncEncoding) {
+ params.timeoutDequeue = DEFAULT_DEQUEUE_TIMEOUT_US;
+ params.runInLooperThread = false;
+ } else {
+ params.timeoutDequeue = 0;
+ params.runInLooperThread = true;
+ }
+ outputParameters.add(params);
+ }
+ return outputParameters;
+ }
+
+ protected EncoderOutputStreamParameters getDefaultEncodingParameters(
+ String inputYuvName,
+ String outputIvfBaseName,
+ String codecMimeType,
+ int encodeSeconds,
+ int frameWidth,
+ int frameHeight,
+ int frameRate,
+ int bitrateMode,
+ int bitrate,
+ boolean syncEncoding) {
+ int[] scaleValues = { 1 };
+ int[] bitrates = { bitrate };
+ return getDefaultEncodingParameterList(
+ inputYuvName,
+ outputIvfBaseName,
+ codecMimeType,
+ encodeSeconds,
+ scaleValues,
+ frameWidth,
+ frameHeight,
+ frameRate,
+ bitrateMode,
+ bitrates,
+ syncEncoding).get(0);
+ }
+
+ /**
+ * Converts (interleaves) YUV420 planar to NV12.
+ * Assumes packed, macroblock-aligned frame with no cropping
+ * (visible/coded row length == stride).
+ */
+ private static byte[] YUV420ToNV(int width, int height, byte[] yuv) {
+ byte[] nv = new byte[yuv.length];
+ // Y plane we just copy.
+ System.arraycopy(yuv, 0, nv, 0, width * height);
+
+ // U & V plane we interleave.
+ int u_offset = width * height;
+ int v_offset = u_offset + u_offset / 4;
+ int nv_offset = width * height;
+ for (int i = 0; i < width * height / 4; i++) {
+ nv[nv_offset++] = yuv[u_offset++];
+ nv[nv_offset++] = yuv[v_offset++];
+ }
+ return nv;
+ }
+
+ /**
+ * Converts (de-interleaves) NV12 to YUV420 planar.
+ * Stride may be greater than width, slice height may be greater than height.
+ */
+ private static byte[] NV12ToYUV420(int width, int height,
+ int stride, int sliceHeight, byte[] nv12) {
+ byte[] yuv = new byte[width * height * 3 / 2];
+
+ // Y plane we just copy.
+ for (int i = 0; i < height; i++) {
+ System.arraycopy(nv12, i * stride, yuv, i * width, width);
+ }
+
+ // U & V plane - de-interleave.
+ int u_offset = width * height;
+ int v_offset = u_offset + u_offset / 4;
+ int nv_offset;
+ for (int i = 0; i < height / 2; i++) {
+ nv_offset = stride * (sliceHeight + i);
+ for (int j = 0; j < width / 2; j++) {
+ yuv[u_offset++] = nv12[nv_offset++];
+ yuv[v_offset++] = nv12[nv_offset++];
+ }
+ }
+ return yuv;
+ }
+
+ /**
+ * Packs YUV420 frame by moving it to a smaller size buffer with stride and slice
+ * height equal to the original frame width and height.
+ */
+ private static byte[] PackYUV420(int width, int height,
+ int stride, int sliceHeight, byte[] src) {
+ byte[] dst = new byte[width * height * 3 / 2];
+ // Y copy.
+ for (int i = 0; i < height; i++) {
+ System.arraycopy(src, i * stride, dst, i * width, width);
+ }
+ // U and V copy.
+ int u_src_offset = stride * sliceHeight;
+ int v_src_offset = u_src_offset + u_src_offset / 4;
+ int u_dst_offset = width * height;
+ int v_dst_offset = u_dst_offset + u_dst_offset / 4;
+ for (int i = 0; i < height / 2; i++) {
+ System.arraycopy(src, u_src_offset + i * (stride / 2),
+ dst, u_dst_offset + i * (width / 2), width / 2);
+ System.arraycopy(src, v_src_offset + i * (stride / 2),
+ dst, v_dst_offset + i * (width / 2), width / 2);
+ }
+ return dst;
+ }
+
+
+ private static void imageUpscale1To2(byte[] src, int srcByteOffset, int srcStride,
+ byte[] dst, int dstByteOffset, int dstWidth, int dstHeight) {
+ for (int i = 0; i < dstHeight/2 - 1; i++) {
+ int dstOffset0 = 2 * i * dstWidth + dstByteOffset;
+ int dstOffset1 = dstOffset0 + dstWidth;
+ int srcOffset0 = i * srcStride + srcByteOffset;
+ int srcOffset1 = srcOffset0 + srcStride;
+ int pixel00 = (int)src[srcOffset0++] & 0xff;
+ int pixel10 = (int)src[srcOffset1++] & 0xff;
+ for (int j = 0; j < dstWidth/2 - 1; j++) {
+ int pixel01 = (int)src[srcOffset0++] & 0xff;
+ int pixel11 = (int)src[srcOffset1++] & 0xff;
+ dst[dstOffset0++] = (byte)pixel00;
+ dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
+ dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
+ dst[dstOffset1++] = (byte)((pixel00 + pixel01 + pixel10 + pixel11 + 2) / 4);
+ pixel00 = pixel01;
+ pixel10 = pixel11;
+ }
+ // last column
+ dst[dstOffset0++] = (byte)pixel00;
+ dst[dstOffset0++] = (byte)pixel00;
+ dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
+ dst[dstOffset1++] = (byte)((pixel00 + pixel10 + 1) / 2);
+ }
+
+ // last row
+ int dstOffset0 = (dstHeight - 2) * dstWidth + dstByteOffset;
+ int dstOffset1 = dstOffset0 + dstWidth;
+ int srcOffset0 = (dstHeight/2 - 1) * srcStride + srcByteOffset;
+ int pixel00 = (int)src[srcOffset0++] & 0xff;
+ for (int j = 0; j < dstWidth/2 - 1; j++) {
+ int pixel01 = (int)src[srcOffset0++] & 0xff;
+ dst[dstOffset0++] = (byte)pixel00;
+ dst[dstOffset0++] = (byte)((pixel00 + pixel01 + 1) / 2);
+ dst[dstOffset1++] = (byte)pixel00;
+ dst[dstOffset1++] = (byte)((pixel00 + pixel01 + 1) / 2);
+ pixel00 = pixel01;
+ }
+ // the very last pixel - bottom right
+ dst[dstOffset0++] = (byte)pixel00;
+ dst[dstOffset0++] = (byte)pixel00;
+ dst[dstOffset1++] = (byte)pixel00;
+ dst[dstOffset1++] = (byte)pixel00;
+ }
+
+ /**
+ * Up-scale image.
+ * Scale factor is defined by source and destination width ratio.
+ * Only 1:2 and 1:4 up-scaling is supported for now.
+ * For 640x480 -> 1280x720 conversion only top 640x360 part of the original
+ * image is scaled.
+ */
+ private static byte[] imageScale(byte[] src, int srcWidth, int srcHeight,
+ int dstWidth, int dstHeight) throws Exception {
+ int srcYSize = srcWidth * srcHeight;
+ int dstYSize = dstWidth * dstHeight;
+ byte[] dst = null;
+ if (dstWidth == 2 * srcWidth && dstHeight <= 2 * srcHeight) {
+ // 1:2 upscale
+ dst = new byte[dstWidth * dstHeight * 3 / 2];
+ imageUpscale1To2(src, 0, srcWidth,
+ dst, 0, dstWidth, dstHeight); // Y
+ imageUpscale1To2(src, srcYSize, srcWidth / 2,
+ dst, dstYSize, dstWidth / 2, dstHeight / 2); // U
+ imageUpscale1To2(src, srcYSize * 5 / 4, srcWidth / 2,
+ dst, dstYSize * 5 / 4, dstWidth / 2, dstHeight / 2); // V
+ } else if (dstWidth == 4 * srcWidth && dstHeight <= 4 * srcHeight) {
+ // 1:4 upscale - in two steps
+ int midWidth = 2 * srcWidth;
+ int midHeight = 2 * srcHeight;
+ byte[] midBuffer = imageScale(src, srcWidth, srcHeight, midWidth, midHeight);
+ dst = imageScale(midBuffer, midWidth, midHeight, dstWidth, dstHeight);
+
+ } else {
+ throw new RuntimeException("Can not find proper scaling function");
+ }
+
+ return dst;
+ }
+
+ private void cacheScaledImage(
+ String srcYuvFilename, int srcResourceId, int srcFrameWidth, int srcFrameHeight,
+ String dstYuvFilename, int dstFrameWidth, int dstFrameHeight) throws Exception {
+ InputStream srcStream = OpenFileOrResourceId(srcYuvFilename, srcResourceId);
+ FileOutputStream dstFile = new FileOutputStream(dstYuvFilename, false);
+ int srcFrameSize = srcFrameWidth * srcFrameHeight * 3 / 2;
+ byte[] srcFrame = new byte[srcFrameSize];
+ byte[] dstFrame = null;
+ Log.d(TAG, "Scale to " + dstFrameWidth + " x " + dstFrameHeight + ". -> " + dstYuvFilename);
+ while (true) {
+ int bytesRead = srcStream.read(srcFrame);
+ if (bytesRead != srcFrame.length) {
+ break;
+ }
+ if (dstFrameWidth == srcFrameWidth && dstFrameHeight == srcFrameHeight) {
+ dstFrame = srcFrame;
+ } else {
+ dstFrame = imageScale(srcFrame, srcFrameWidth, srcFrameHeight,
+ dstFrameWidth, dstFrameHeight);
+ }
+ dstFile.write(dstFrame);
+ }
+ srcStream.close();
+ dstFile.close();
+ }
+
+
+ /**
+ * A basic check if an encoded stream is decodable.
+ *
+ * The most basic confirmation we can get about a frame
+ * being properly encoded is trying to decode it.
+ * (Especially in realtime mode encode output is non-
+ * deterministic, therefore a more thorough check like
+ * md5 sum comparison wouldn't work.)
+ *
+ * Indeed, MediaCodec will raise an IllegalStateException
+ * whenever vpx decoder fails to decode a frame, and
+ * this test uses that fact to verify the bitstream.
+ *
+ * @param inputIvfFilename The name of the IVF file containing encoded bitsream.
+ * @param outputYuvFilename The name of the output YUV file (optional).
+ * @param frameRate Frame rate of input file in frames per second
+ * @param forceGoogleDecoder Force to use Google VPx decoder.
+ */
+ protected ArrayList<MediaCodec.BufferInfo> decode(
+ String inputIvfFilename,
+ String outputYuvFilename,
+ String codecMimeType,
+ int frameRate,
+ boolean forceGoogleDecoder) throws Exception {
+ ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+
+ // Open input/output.
+ IvfReader ivf = new IvfReader(inputIvfFilename);
+ int frameWidth = ivf.getWidth();
+ int frameHeight = ivf.getHeight();
+ int frameCount = ivf.getFrameCount();
+ int frameStride = frameWidth;
+ int frameSliceHeight = frameHeight;
+ assertTrue(frameWidth > 0);
+ assertTrue(frameHeight > 0);
+ assertTrue(frameCount > 0);
+
+ // Create decoder.
+ MediaFormat format = MediaFormat.createVideoFormat(
+ codecMimeType, ivf.getWidth(), ivf.getHeight());
+ CodecProperties properties = getVpxCodecProperties(
+ false /* encoder */, format, forceGoogleDecoder);
+ if (properties == null) {
+ ivf.close();
+ return null;
+ }
+ int frameColorFormat = properties.colorFormat;
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+
+ FileOutputStream yuv = null;
+ if (outputYuvFilename != null) {
+ yuv = new FileOutputStream(outputYuvFilename, false);
+ }
+
+ Log.d(TAG, "Creating decoder " + properties.codecName +
+ ". Color format: 0x" + Integer.toHexString(frameColorFormat) +
+ ". " + frameWidth + " x " + frameHeight);
+ Log.d(TAG, " Format: " + format);
+ Log.d(TAG, " In: " + inputIvfFilename + ". Out:" + outputYuvFilename);
+ MediaCodec decoder = MediaCodec.createByCodecName(properties.codecName);
+ decoder.configure(format,
+ null, // surface
+ null, // crypto
+ 0); // flags
+ decoder.start();
+
+ ByteBuffer[] inputBuffers = decoder.getInputBuffers();
+ ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
+ MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
+
+ // decode loop
+ int inputFrameIndex = 0;
+ int outputFrameIndex = 0;
+ long inPresentationTimeUs = 0;
+ long outPresentationTimeUs = 0;
+ boolean sawOutputEOS = false;
+ boolean sawInputEOS = false;
+
+ while (!sawOutputEOS) {
+ if (!sawInputEOS) {
+ int inputBufIndex = decoder.dequeueInputBuffer(DEFAULT_DEQUEUE_TIMEOUT_US);
+ if (inputBufIndex >= 0) {
+ byte[] frame = ivf.readFrame(inputFrameIndex);
+
+ if (inputFrameIndex == frameCount - 1) {
+ Log.d(TAG, " Input EOS for frame # " + inputFrameIndex);
+ sawInputEOS = true;
+ }
+
+ inputBuffers[inputBufIndex].clear();
+ inputBuffers[inputBufIndex].put(frame);
+ inputBuffers[inputBufIndex].rewind();
+ inPresentationTimeUs = (inputFrameIndex * 1000000) / frameRate;
+
+ decoder.queueInputBuffer(
+ inputBufIndex,
+ 0, // offset
+ frame.length,
+ inPresentationTimeUs,
+ sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+ inputFrameIndex++;
+ }
+ }
+
+ int result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
+ while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
+ result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ outputBuffers = decoder.getOutputBuffers();
+ } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ // Process format change
+ format = decoder.getOutputFormat();
+ frameWidth = format.getInteger(MediaFormat.KEY_WIDTH);
+ frameHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+ frameColorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+ Log.d(TAG, "Decoder output format change. Color: 0x" +
+ Integer.toHexString(frameColorFormat));
+ Log.d(TAG, "Format: " + format.toString());
+
+ // Parse frame and slice height from undocumented values
+ if (format.containsKey("stride")) {
+ frameStride = format.getInteger("stride");
+ } else {
+ frameStride = frameWidth;
+ }
+ if (format.containsKey("slice-height")) {
+ frameSliceHeight = format.getInteger("slice-height");
+ } else {
+ frameSliceHeight = frameHeight;
+ }
+ Log.d(TAG, "Frame stride and slice height: " + frameStride +
+ " x " + frameSliceHeight);
+ frameStride = Math.max(frameWidth, frameStride);
+ frameSliceHeight = Math.max(frameHeight, frameSliceHeight);
+ }
+ result = decoder.dequeueOutputBuffer(bufferInfo, DEFAULT_DEQUEUE_TIMEOUT_US);
+ }
+ if (result >= 0) {
+ int outputBufIndex = result;
+ outPresentationTimeUs = bufferInfo.presentationTimeUs;
+ Log.v(TAG, "Writing buffer # " + outputFrameIndex +
+ ". Size: " + bufferInfo.size +
+ ". InTime: " + (inPresentationTimeUs + 500)/1000 +
+ ". OutTime: " + (outPresentationTimeUs + 500)/1000);
+ if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ sawOutputEOS = true;
+ Log.d(TAG, " Output EOS for frame # " + outputFrameIndex);
+ }
+
+ if (bufferInfo.size > 0) {
+ // Save decoder output to yuv file.
+ if (yuv != null) {
+ byte[] frame = new byte[bufferInfo.size];
+ outputBuffers[outputBufIndex].position(bufferInfo.offset);
+ outputBuffers[outputBufIndex].get(frame, 0, bufferInfo.size);
+ // Convert NV12 to YUV420 if necessary.
+ if (frameColorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
+ frame = NV12ToYUV420(frameWidth, frameHeight,
+ frameStride, frameSliceHeight, frame);
+ }
+ int writeLength = Math.min(frameWidth * frameHeight * 3 / 2, frame.length);
+ // Pack frame if necessary.
+ if (writeLength < frame.length &&
+ (frameStride > frameWidth || frameSliceHeight > frameHeight)) {
+ frame = PackYUV420(frameWidth, frameHeight,
+ frameStride, frameSliceHeight, frame);
+ }
+ yuv.write(frame, 0, writeLength);
+ }
+ outputFrameIndex++;
+
+ // Update statistics - store presentation time delay in offset
+ long presentationTimeUsDelta = inPresentationTimeUs - outPresentationTimeUs;
+ MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+ bufferInfoCopy.set((int)presentationTimeUsDelta, bufferInfo.size,
+ outPresentationTimeUs, bufferInfo.flags);
+ bufferInfos.add(bufferInfoCopy);
+ }
+ decoder.releaseOutputBuffer(outputBufIndex, false);
+ }
+ }
+ decoder.stop();
+ decoder.release();
+ ivf.close();
+ if (yuv != null) {
+ yuv.close();
+ }
+
+ return bufferInfos;
+ }
+
+
+ /**
+ * Helper function to return InputStream from either filename (if set)
+ * or resource id (if filename is not set).
+ */
+ private InputStream OpenFileOrResourceId(String filename, int resourceId) throws Exception {
+ if (filename != null) {
+ return new FileInputStream(filename);
+ }
+ return mResources.openRawResource(resourceId);
+ }
+
+ /**
+ * Results of frame encoding.
+ */
+ protected class MediaEncoderOutput {
+ public long inPresentationTimeUs;
+ public long outPresentationTimeUs;
+ public boolean outputGenerated;
+ public int flags;
+ public byte[] buffer;
+ }
+
+ protected class MediaEncoderAsyncHelper {
+ private final EncoderOutputStreamParameters mStreamParams;
+ private final CodecProperties mProperties;
+ private final ArrayList<MediaCodec.BufferInfo> mBufferInfos;
+ private final IvfWriter mIvf;
+ private final byte[] mSrcFrame;
+
+ private InputStream mYuvStream;
+ private int mInputFrameIndex;
+
+ MediaEncoderAsyncHelper(
+ EncoderOutputStreamParameters streamParams,
+ CodecProperties properties,
+ ArrayList<MediaCodec.BufferInfo> bufferInfos,
+ IvfWriter ivf)
+ throws Exception {
+ mStreamParams = streamParams;
+ mProperties = properties;
+ mBufferInfos = bufferInfos;
+ mIvf = ivf;
+
+ int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
+ mSrcFrame = new byte[srcFrameSize];
+
+ mYuvStream = OpenFileOrResourceId(
+ streamParams.inputYuvFilename, streamParams.inputResourceId);
+ }
+
+ public byte[] getInputFrame() {
+ // Check EOS
+ if (mStreamParams.frameCount == 0
+ || (mStreamParams.frameCount > 0
+ && mInputFrameIndex >= mStreamParams.frameCount)) {
+ Log.d(TAG, "---Sending EOS empty frame for frame # " + mInputFrameIndex);
+ return null;
+ }
+
+ try {
+ int bytesRead = mYuvStream.read(mSrcFrame);
+
+ if (bytesRead == -1) {
+ // rewind to beginning of file
+ mYuvStream.close();
+ mYuvStream = OpenFileOrResourceId(
+ mStreamParams.inputYuvFilename, mStreamParams.inputResourceId);
+ bytesRead = mYuvStream.read(mSrcFrame);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to read YUV file.");
+ return null;
+ }
+ mInputFrameIndex++;
+
+ // Convert YUV420 to NV12 if necessary
+ if (mProperties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
+ return YUV420ToNV(mStreamParams.frameWidth, mStreamParams.frameHeight,
+ mSrcFrame);
+ } else {
+ return mSrcFrame;
+ }
+ }
+
+ public boolean saveOutputFrame(MediaEncoderOutput out) {
+ if (out.outputGenerated) {
+ if (out.buffer.length > 0) {
+ // Save frame
+ try {
+ mIvf.writeFrame(out.buffer, out.outPresentationTimeUs);
+ } catch (Exception e) {
+ Log.d(TAG, "Failed to write frame");
+ return true;
+ }
+
+ // Update statistics - store presentation time delay in offset
+ long presentationTimeUsDelta = out.inPresentationTimeUs -
+ out.outPresentationTimeUs;
+ MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+ bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
+ out.outPresentationTimeUs, out.flags);
+ mBufferInfos.add(bufferInfoCopy);
+ }
+ // Detect output EOS
+ if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ Log.d(TAG, "----Output EOS ");
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Video encoder wrapper class.
+ * Allows to run the encoder either in a callee's thread or in a looper thread
+ * using buffer dequeue ready notification callbacks.
+ *
+ * Function feedInput() is used to send raw video frame to the encoder input. When encoder
+ * is configured to run in async mode the function will run in a looper thread.
+ * Encoded frame can be retrieved by calling getOutput() function.
+ */
+ protected class MediaEncoderAsync extends Thread {
+ private int mId;
+ private MediaCodec mCodec;
+ private MediaFormat mFormat;
+ private ByteBuffer[] mInputBuffers;
+ private ByteBuffer[] mOutputBuffers;
+ private int mInputFrameIndex;
+ private int mOutputFrameIndex;
+ private int mInputBufIndex;
+ private int mFrameRate;
+ private long mTimeout;
+ private MediaCodec.BufferInfo mBufferInfo;
+ private long mInPresentationTimeUs;
+ private long mOutPresentationTimeUs;
+ private boolean mAsync;
+ // Flag indicating if input frame was consumed by the encoder in feedInput() call.
+ private boolean mConsumedInput;
+ // Result of frame encoding returned by getOutput() call.
+ private MediaEncoderOutput mOutput;
+ // Object used to signal that looper thread has started and Handler instance associated
+ // with looper thread has been allocated.
+ private final Object mThreadEvent = new Object();
+ // Object used to signal that MediaCodec buffer dequeue notification callback
+ // was received.
+ private final Object mCallbackEvent = new Object();
+ private Handler mHandler;
+ private boolean mCallbackReceived;
+ private MediaEncoderAsyncHelper mHelper;
+ private final Object mCompletionEvent = new Object();
+ private boolean mCompleted;
+
+ private MediaCodec.Callback mCallback = new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(MediaCodec codec, int index) {
+ if (mHelper == null) {
+ Log.e(TAG, "async helper not available");
+ return;
+ }
+
+ byte[] encFrame = mHelper.getInputFrame();
+ boolean inputEOS = (encFrame == null);
+
+ int encFrameLength = 0;
+ int flags = 0;
+ if (inputEOS) {
+ flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ } else {
+ encFrameLength = encFrame.length;
+
+ ByteBuffer byteBuffer = mCodec.getInputBuffer(index);
+ byteBuffer.put(encFrame);
+ byteBuffer.rewind();
+
+ mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
+
+ Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
+ ". InTime: " + (mInPresentationTimeUs + 500)/1000);
+
+ mInputFrameIndex++;
+ }
+
+ mCodec.queueInputBuffer(
+ index,
+ 0, // offset
+ encFrameLength, // size
+ mInPresentationTimeUs,
+ flags);
+ }
+
+ @Override
+ public void onOutputBufferAvailable(MediaCodec codec,
+ int index, MediaCodec.BufferInfo info) {
+ if (mHelper == null) {
+ Log.e(TAG, "async helper not available");
+ return;
+ }
+
+ MediaEncoderOutput out = new MediaEncoderOutput();
+
+ out.buffer = new byte[info.size];
+ ByteBuffer outputBuffer = mCodec.getOutputBuffer(index);
+ outputBuffer.get(out.buffer, 0, info.size);
+ mOutPresentationTimeUs = info.presentationTimeUs;
+
+ String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
+ if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
+ logStr += " CONFIG. ";
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
+ logStr += " KEY. ";
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ logStr += " EOS. ";
+ }
+ logStr += " Size: " + info.size;
+ logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
+ ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
+ Log.v(TAG, logStr);
+
+ if (mOutputFrameIndex == 0 &&
+ ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
+ throw new RuntimeException("First frame is not a sync frame.");
+ }
+
+ if (info.size > 0) {
+ mOutputFrameIndex++;
+ out.inPresentationTimeUs = mInPresentationTimeUs;
+ out.outPresentationTimeUs = mOutPresentationTimeUs;
+ }
+ mCodec.releaseOutputBuffer(index, false);
+
+ out.flags = info.flags;
+ out.outputGenerated = true;
+
+ if (mHelper.saveOutputFrame(out)) {
+ // output EOS
+ signalCompletion();
+ }
+ }
+
+ @Override
+ public void onError(MediaCodec codec, CodecException e) {
+ Log.e(TAG, "onError: " + e
+ + ", transient " + e.isTransient()
+ + ", recoverable " + e.isRecoverable()
+ + ", error " + e.getErrorCode());
+ }
+
+ @Override
+ public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+ Log.i(TAG, "onOutputFormatChanged: " + format.toString());
+ }
+ };
+
+ private synchronized void requestStart() throws Exception {
+ mHandler = null;
+ start();
+ // Wait for Hander allocation
+ synchronized (mThreadEvent) {
+ while (mHandler == null) {
+ mThreadEvent.wait();
+ }
+ }
+ }
+
+ public void setAsyncHelper(MediaEncoderAsyncHelper helper) {
+ mHelper = helper;
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ synchronized (mThreadEvent) {
+ mHandler = new Handler();
+ mThreadEvent.notify();
+ }
+ Looper.loop();
+ }
+
+ private void runCallable(final Callable<?> callable) throws Exception {
+ if (mAsync) {
+ final Exception[] exception = new Exception[1];
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ mHandler.post( new Runnable() {
+ @Override
+ public void run() {
+ try {
+ callable.call();
+ } catch (Exception e) {
+ exception[0] = e;
+ } finally {
+ countDownLatch.countDown();
+ }
+ }
+ } );
+
+ // Wait for task completion
+ countDownLatch.await();
+ if (exception[0] != null) {
+ throw exception[0];
+ }
+ } else {
+ callable.call();
+ }
+ }
+
+ private synchronized void requestStop() throws Exception {
+ mHandler.post( new Runnable() {
+ @Override
+ public void run() {
+ // This will run on the Looper thread
+ Log.v(TAG, "MediaEncoder looper quitting");
+ Looper.myLooper().quitSafely();
+ }
+ } );
+ // Wait for completion
+ join();
+ mHandler = null;
+ }
+
+ private void createCodecInternal(final String name,
+ final MediaFormat format, final long timeout) throws Exception {
+ mBufferInfo = new MediaCodec.BufferInfo();
+ mFormat = format;
+ mFrameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+ mTimeout = timeout;
+ mInputFrameIndex = 0;
+ mOutputFrameIndex = 0;
+ mInPresentationTimeUs = 0;
+ mOutPresentationTimeUs = 0;
+
+ mCodec = MediaCodec.createByCodecName(name);
+ if (mAsync) {
+ mCodec.setCallback(mCallback);
+ }
+ mCodec.configure(mFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ mCodec.start();
+
+ // get the cached input/output only in sync mode
+ if (!mAsync) {
+ mInputBuffers = mCodec.getInputBuffers();
+ mOutputBuffers = mCodec.getOutputBuffers();
+ }
+ }
+
+ public void createCodec(int id, final String name, final MediaFormat format,
+ final long timeout, boolean async) throws Exception {
+ mId = id;
+ mAsync = async;
+ if (mAsync) {
+ requestStart(); // start looper thread
+ }
+ runCallable( new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ createCodecInternal(name, format, timeout);
+ return null;
+ }
+ } );
+ }
+
+ private void feedInputInternal(final byte[] encFrame, final boolean inputEOS) {
+ mConsumedInput = false;
+ // Feed input
+ mInputBufIndex = mCodec.dequeueInputBuffer(mTimeout);
+
+ if (mInputBufIndex >= 0) {
+ mInputBuffers[mInputBufIndex].clear();
+ mInputBuffers[mInputBufIndex].put(encFrame);
+ mInputBuffers[mInputBufIndex].rewind();
+ int encFrameLength = encFrame.length;
+ int flags = 0;
+ if (inputEOS) {
+ encFrameLength = 0;
+ flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+ if (!inputEOS) {
+ Log.v(TAG, "Enc" + mId + ". Frame in # " + mInputFrameIndex +
+ ". InTime: " + (mInPresentationTimeUs + 500)/1000);
+ mInPresentationTimeUs = (mInputFrameIndex * 1000000) / mFrameRate;
+ mInputFrameIndex++;
+ }
+
+ mCodec.queueInputBuffer(
+ mInputBufIndex,
+ 0, // offset
+ encFrameLength, // size
+ mInPresentationTimeUs,
+ flags);
+
+ mConsumedInput = true;
+ } else {
+ Log.v(TAG, "In " + mId + " - TRY_AGAIN_LATER");
+ }
+ mCallbackReceived = false;
+ }
+
+ public boolean feedInput(final byte[] encFrame, final boolean inputEOS) throws Exception {
+ runCallable( new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ feedInputInternal(encFrame, inputEOS);
+ return null;
+ }
+ } );
+ return mConsumedInput;
+ }
+
+ private void getOutputInternal() {
+ mOutput = new MediaEncoderOutput();
+ mOutput.inPresentationTimeUs = mInPresentationTimeUs;
+ mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
+ mOutput.outputGenerated = false;
+
+ // Get output from the encoder
+ int result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
+ while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
+ result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ mOutputBuffers = mCodec.getOutputBuffers();
+ } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ mFormat = mCodec.getOutputFormat();
+ Log.d(TAG, "Format changed: " + mFormat.toString());
+ }
+ result = mCodec.dequeueOutputBuffer(mBufferInfo, mTimeout);
+ }
+ if (result == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.v(TAG, "Out " + mId + " - TRY_AGAIN_LATER");
+ }
+
+ if (result >= 0) {
+ int outputBufIndex = result;
+ mOutput.buffer = new byte[mBufferInfo.size];
+ mOutputBuffers[outputBufIndex].position(mBufferInfo.offset);
+ mOutputBuffers[outputBufIndex].get(mOutput.buffer, 0, mBufferInfo.size);
+ mOutPresentationTimeUs = mBufferInfo.presentationTimeUs;
+
+ String logStr = "Enc" + mId + ". Frame # " + mOutputFrameIndex;
+ if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
+ logStr += " CONFIG. ";
+ }
+ if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
+ logStr += " KEY. ";
+ }
+ if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ logStr += " EOS. ";
+ }
+ logStr += " Size: " + mBufferInfo.size;
+ logStr += ". InTime: " + (mInPresentationTimeUs + 500)/1000 +
+ ". OutTime: " + (mOutPresentationTimeUs + 500)/1000;
+ Log.v(TAG, logStr);
+ if (mOutputFrameIndex == 0 &&
+ ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) == 0) ) {
+ throw new RuntimeException("First frame is not a sync frame.");
+ }
+
+ if (mBufferInfo.size > 0) {
+ mOutputFrameIndex++;
+ mOutput.outPresentationTimeUs = mOutPresentationTimeUs;
+ }
+ mCodec.releaseOutputBuffer(outputBufIndex, false);
+
+ mOutput.flags = mBufferInfo.flags;
+ mOutput.outputGenerated = true;
+ }
+ mCallbackReceived = false;
+ }
+
+ public MediaEncoderOutput getOutput() throws Exception {
+ runCallable( new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ getOutputInternal();
+ return null;
+ }
+ } );
+ return mOutput;
+ }
+
+ public void forceSyncFrame() throws Exception {
+ final Bundle syncFrame = new Bundle();
+ syncFrame.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
+ runCallable( new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ mCodec.setParameters(syncFrame);
+ return null;
+ }
+ } );
+ }
+
+ public void updateBitrate(int bitrate) throws Exception {
+ final Bundle bitrateUpdate = new Bundle();
+ bitrateUpdate.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bitrate);
+ runCallable( new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ mCodec.setParameters(bitrateUpdate);
+ return null;
+ }
+ } );
+ }
+
+
+ public void waitForBufferEvent() throws Exception {
+ Log.v(TAG, "----Enc" + mId + " waiting for bufferEvent");
+ if (mAsync) {
+ synchronized (mCallbackEvent) {
+ if (!mCallbackReceived) {
+ mCallbackEvent.wait(1000); // wait 1 sec for a callback
+ // throw an exception if callback was not received
+ if (!mCallbackReceived) {
+ throw new RuntimeException("MediaCodec callback was not received");
+ }
+ }
+ }
+ } else {
+ Thread.sleep(5);
+ }
+ Log.v(TAG, "----Waiting for bufferEvent done");
+ }
+
+
+ public void waitForCompletion(long timeoutMs) throws Exception {
+ synchronized (mCompletionEvent) {
+ long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
+
+ while (!mCompleted) {
+ mCompletionEvent.wait(timeoutExpiredMs - System.currentTimeMillis());
+ if (System.currentTimeMillis() >= timeoutExpiredMs) {
+ throw new RuntimeException("encoding has timed out!");
+ }
+ }
+ }
+ }
+
+ public void signalCompletion() {
+ synchronized (mCompletionEvent) {
+ mCompleted = true;
+ mCompletionEvent.notify();
+ }
+ }
+
+ public void deleteCodec() throws Exception {
+ runCallable( new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ mCodec.stop();
+ mCodec.release();
+ return null;
+ }
+ } );
+ if (mAsync) {
+ requestStop(); // Stop looper thread
+ }
+ }
+ }
+
+ /**
+ * Vpx encoding loop supporting encoding single streams with an option
+ * to run in a looper thread and use buffer ready notification callbacks.
+ *
+ * Output stream is described by encodingParams parameters.
+ *
+ * MediaCodec will raise an IllegalStateException
+ * whenever vpx encoder fails to encode a frame.
+ *
+ * Color format of input file should be YUV420, and frameWidth,
+ * frameHeight should be supplied correctly as raw input file doesn't
+ * include any header data.
+ *
+ * @param streamParams Structure with encoder parameters
+ * @return Returns array of encoded frames information for each frame.
+ */
+ protected ArrayList<MediaCodec.BufferInfo> encode(
+ EncoderOutputStreamParameters streamParams) throws Exception {
+
+ ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+ Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
+ streamParams.frameHeight);
+ int bitrate = streamParams.bitrateSet[0];
+
+ // Create minimal media format signifying desired output.
+ MediaFormat format = MediaFormat.createVideoFormat(
+ streamParams.codecMimeType, streamParams.frameWidth,
+ streamParams.frameHeight);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+ CodecProperties properties = getVpxCodecProperties(
+ true, format, streamParams.forceGoogleEncoder);
+ if (properties == null) {
+ return null;
+ }
+
+ // Open input/output
+ InputStream yuvStream = OpenFileOrResourceId(
+ streamParams.inputYuvFilename, streamParams.inputResourceId);
+ IvfWriter ivf = new IvfWriter(
+ streamParams.outputIvfFilename, streamParams.codecMimeType,
+ streamParams.frameWidth, streamParams.frameHeight);
+
+ // Create a media format signifying desired output.
+ if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
+ format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
+ }
+ if (streamParams.temporalLayers > 0) {
+ format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
+ }
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
+ int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
+ streamParams.frameRate;
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+
+ // Create encoder
+ Log.d(TAG, "Creating encoder " + properties.codecName +
+ ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
+ streamParams.frameWidth + " x " + streamParams.frameHeight +
+ ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
+ ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
+ ". Key frame:" + syncFrameInterval * streamParams.frameRate +
+ ". Force keyFrame: " + streamParams.syncForceFrameInterval);
+ Log.d(TAG, " Format: " + format);
+ Log.d(TAG, " Output ivf:" + streamParams.outputIvfFilename);
+ MediaEncoderAsync codec = new MediaEncoderAsync();
+ codec.createCodec(0, properties.codecName, format,
+ streamParams.timeoutDequeue, streamParams.runInLooperThread);
+
+ // encode loop
+ boolean sawInputEOS = false; // no more data
+ boolean consumedInputEOS = false; // EOS flag is consumed dy encoder
+ boolean sawOutputEOS = false;
+ boolean inputConsumed = true;
+ int inputFrameIndex = 0;
+ int lastBitrate = bitrate;
+ int srcFrameSize = streamParams.frameWidth * streamParams.frameHeight * 3 / 2;
+ byte[] srcFrame = new byte[srcFrameSize];
+
+ while (!sawOutputEOS) {
+
+ // Read and feed input frame
+ if (!consumedInputEOS) {
+
+ // Read new input buffers - if previous input was consumed and no EOS
+ if (inputConsumed && !sawInputEOS) {
+ int bytesRead = yuvStream.read(srcFrame);
+
+ // Check EOS
+ if (streamParams.frameCount > 0 && inputFrameIndex >= streamParams.frameCount) {
+ sawInputEOS = true;
+ Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
+ }
+
+ if (!sawInputEOS && bytesRead == -1) {
+ if (streamParams.frameCount == 0) {
+ sawInputEOS = true;
+ Log.d(TAG, "---Sending EOS empty frame for frame # " + inputFrameIndex);
+ } else {
+ yuvStream.close();
+ yuvStream = OpenFileOrResourceId(
+ streamParams.inputYuvFilename, streamParams.inputResourceId);
+ bytesRead = yuvStream.read(srcFrame);
+ }
+ }
+
+ // Force sync frame if syncForceFrameinterval is set.
+ if (!sawInputEOS && inputFrameIndex > 0 &&
+ streamParams.syncForceFrameInterval > 0 &&
+ (inputFrameIndex % streamParams.syncForceFrameInterval) == 0) {
+ Log.d(TAG, "---Requesting sync frame # " + inputFrameIndex);
+ codec.forceSyncFrame();
+ }
+
+ // Dynamic bitrate change.
+ if (!sawInputEOS && streamParams.bitrateSet.length > inputFrameIndex) {
+ int newBitrate = streamParams.bitrateSet[inputFrameIndex];
+ if (newBitrate != lastBitrate) {
+ Log.d(TAG, "--- Requesting new bitrate " + newBitrate +
+ " for frame " + inputFrameIndex);
+ codec.updateBitrate(newBitrate);
+ lastBitrate = newBitrate;
+ }
+ }
+
+ // Convert YUV420 to NV12 if necessary
+ if (properties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
+ srcFrame = YUV420ToNV(streamParams.frameWidth, streamParams.frameHeight,
+ srcFrame);
+ }
+ }
+
+ inputConsumed = codec.feedInput(srcFrame, sawInputEOS);
+ if (inputConsumed) {
+ inputFrameIndex++;
+ consumedInputEOS = sawInputEOS;
+ }
+ }
+
+ // Get output from the encoder
+ MediaEncoderOutput out = codec.getOutput();
+ if (out.outputGenerated) {
+ // Detect output EOS
+ if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ Log.d(TAG, "----Output EOS ");
+ sawOutputEOS = true;
+ }
+
+ if (out.buffer.length > 0) {
+ // Save frame
+ ivf.writeFrame(out.buffer, out.outPresentationTimeUs);
+
+ // Update statistics - store presentation time delay in offset
+ long presentationTimeUsDelta = out.inPresentationTimeUs -
+ out.outPresentationTimeUs;
+ MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+ bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
+ out.outPresentationTimeUs, out.flags);
+ bufferInfos.add(bufferInfoCopy);
+ }
+ }
+
+ // If codec is not ready to accept input/poutput - wait for buffer ready callback
+ if ((!inputConsumed || consumedInputEOS) && !out.outputGenerated) {
+ codec.waitForBufferEvent();
+ }
+ }
+
+ codec.deleteCodec();
+ ivf.close();
+ yuvStream.close();
+
+ return bufferInfos;
+ }
+
+ /**
+ * Vpx encoding run in a looper thread and use buffer ready callbacks.
+ *
+ * Output stream is described by encodingParams parameters.
+ *
+ * MediaCodec will raise an IllegalStateException
+ * whenever vpx encoder fails to encode a frame.
+ *
+ * Color format of input file should be YUV420, and frameWidth,
+ * frameHeight should be supplied correctly as raw input file doesn't
+ * include any header data.
+ *
+ * @param streamParams Structure with encoder parameters
+ * @return Returns array of encoded frames information for each frame.
+ */
+ protected ArrayList<MediaCodec.BufferInfo> encodeAsync(
+ EncoderOutputStreamParameters streamParams) throws Exception {
+ if (!streamParams.runInLooperThread) {
+ throw new RuntimeException("encodeAsync should run with a looper thread!");
+ }
+
+ ArrayList<MediaCodec.BufferInfo> bufferInfos = new ArrayList<MediaCodec.BufferInfo>();
+ Log.d(TAG, "Source resolution: "+streamParams.frameWidth + " x " +
+ streamParams.frameHeight);
+ int bitrate = streamParams.bitrateSet[0];
+
+ // Create minimal media format signifying desired output.
+ MediaFormat format = MediaFormat.createVideoFormat(
+ streamParams.codecMimeType, streamParams.frameWidth,
+ streamParams.frameHeight);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+ CodecProperties properties = getVpxCodecProperties(
+ true, format, streamParams.forceGoogleEncoder);
+ if (properties == null) {
+ return null;
+ }
+
+ // Open input/output
+ IvfWriter ivf = new IvfWriter(
+ streamParams.outputIvfFilename, streamParams.codecMimeType,
+ streamParams.frameWidth, streamParams.frameHeight);
+
+ // Create a media format signifying desired output.
+ if (streamParams.bitrateType == VIDEO_ControlRateConstant) {
+ format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
+ }
+ if (streamParams.temporalLayers > 0) {
+ format.setInteger("ts-layers", streamParams.temporalLayers); // 1 temporal layer
+ }
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, streamParams.frameRate);
+ int syncFrameInterval = (streamParams.syncFrameInterval + streamParams.frameRate/2) /
+ streamParams.frameRate;
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+
+ // Create encoder
+ Log.d(TAG, "Creating encoder " + properties.codecName +
+ ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
+ streamParams.frameWidth + " x " + streamParams.frameHeight +
+ ". Bitrate: " + bitrate + " Bitrate type: " + streamParams.bitrateType +
+ ". Fps:" + streamParams.frameRate + ". TS Layers: " + streamParams.temporalLayers +
+ ". Key frame:" + syncFrameInterval * streamParams.frameRate +
+ ". Force keyFrame: " + streamParams.syncForceFrameInterval);
+ Log.d(TAG, " Format: " + format);
+ Log.d(TAG, " Output ivf:" + streamParams.outputIvfFilename);
+
+ MediaEncoderAsync codec = new MediaEncoderAsync();
+ MediaEncoderAsyncHelper helper = new MediaEncoderAsyncHelper(
+ streamParams, properties, bufferInfos, ivf);
+
+ codec.setAsyncHelper(helper);
+ codec.createCodec(0, properties.codecName, format,
+ streamParams.timeoutDequeue, streamParams.runInLooperThread);
+ codec.waitForCompletion(DEFAULT_ENCODE_TIMEOUT_MS);
+
+ codec.deleteCodec();
+ ivf.close();
+
+ return bufferInfos;
+ }
+
+ /**
+ * Vpx encoding loop supporting encoding multiple streams at a time.
+ * Each output stream is described by encodingParams parameters allowing
+ * simultaneous encoding of various resolutions, bitrates with an option to
+ * control key frame and dynamic bitrate for each output stream indepandently.
+ *
+ * MediaCodec will raise an IllegalStateException
+ * whenever vpx encoder fails to encode a frame.
+ *
+ * Color format of input file should be YUV420, and frameWidth,
+ * frameHeight should be supplied correctly as raw input file doesn't
+ * include any header data.
+ *
+ * @param srcFrameWidth Frame width of input yuv file
+ * @param srcFrameHeight Frame height of input yuv file
+ * @param encodingParams Encoder parameters
+ * @return Returns 2D array of encoded frames information for each stream and
+ * for each frame.
+ */
+ protected ArrayList<ArrayList<MediaCodec.BufferInfo>> encodeSimulcast(
+ int srcFrameWidth,
+ int srcFrameHeight,
+ ArrayList<EncoderOutputStreamParameters> encodingParams) throws Exception {
+ int numEncoders = encodingParams.size();
+
+ // Create arrays of input/output, formats, bitrates etc
+ ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos =
+ new ArrayList<ArrayList<MediaCodec.BufferInfo>>(numEncoders);
+ InputStream yuvStream[] = new InputStream[numEncoders];
+ IvfWriter[] ivf = new IvfWriter[numEncoders];
+ FileOutputStream[] yuvScaled = new FileOutputStream[numEncoders];
+ MediaFormat[] format = new MediaFormat[numEncoders];
+ MediaEncoderAsync[] codec = new MediaEncoderAsync[numEncoders];
+ int[] inputFrameIndex = new int[numEncoders];
+ boolean[] sawInputEOS = new boolean[numEncoders];
+ boolean[] consumedInputEOS = new boolean[numEncoders];
+ boolean[] inputConsumed = new boolean[numEncoders];
+ boolean[] bufferConsumed = new boolean[numEncoders];
+ boolean[] sawOutputEOS = new boolean[numEncoders];
+ byte[][] srcFrame = new byte[numEncoders][];
+ boolean sawOutputEOSTotal = false;
+ boolean bufferConsumedTotal = false;
+ CodecProperties[] codecProperties = new CodecProperties[numEncoders];
+
+ numEncoders = 0;
+ for (EncoderOutputStreamParameters params : encodingParams) {
+ int i = numEncoders;
+ Log.d(TAG, "Source resolution: " + params.frameWidth + " x " +
+ params.frameHeight);
+ int bitrate = params.bitrateSet[0];
+
+ // Create minimal media format signifying desired output.
+ format[i] = MediaFormat.createVideoFormat(
+ params.codecMimeType, params.frameWidth,
+ params.frameHeight);
+ format[i].setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+ CodecProperties properties = getVpxCodecProperties(
+ true, format[i], params.forceGoogleEncoder);
+ if (properties == null) {
+ continue;
+ }
+
+ // Check if scaled image was created
+ int scale = params.frameWidth / srcFrameWidth;
+ if (!mScaledImages.contains(scale)) {
+ // resize image
+ cacheScaledImage(params.inputYuvFilename, params.inputResourceId,
+ srcFrameWidth, srcFrameHeight,
+ params.scaledYuvFilename, params.frameWidth, params.frameHeight);
+ mScaledImages.add(scale);
+ }
+
+ // Create buffer info storage
+ bufferInfos.add(new ArrayList<MediaCodec.BufferInfo>());
+
+ // Create YUV reader
+ yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
+
+ // Create IVF writer
+ ivf[i] = new IvfWriter(
+ params.outputIvfFilename, params.codecMimeType,
+ params.frameWidth, params.frameHeight);
+
+ // Frame buffer
+ int frameSize = params.frameWidth * params.frameHeight * 3 / 2;
+ srcFrame[i] = new byte[frameSize];
+
+ // Create a media format signifying desired output.
+ if (params.bitrateType == VIDEO_ControlRateConstant) {
+ format[i].setInteger("bitrate-mode", VIDEO_ControlRateConstant); // set CBR
+ }
+ if (params.temporalLayers > 0) {
+ format[i].setInteger("ts-layers", params.temporalLayers); // 1 temporal layer
+ }
+ format[i].setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
+ format[i].setInteger(MediaFormat.KEY_FRAME_RATE, params.frameRate);
+ int syncFrameInterval = (params.syncFrameInterval + params.frameRate/2) /
+ params.frameRate; // in sec
+ format[i].setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, syncFrameInterval);
+ // Create encoder
+ Log.d(TAG, "Creating encoder #" + i +" : " + properties.codecName +
+ ". Color format: 0x" + Integer.toHexString(properties.colorFormat)+ " : " +
+ params.frameWidth + " x " + params.frameHeight +
+ ". Bitrate: " + bitrate + " Bitrate type: " + params.bitrateType +
+ ". Fps:" + params.frameRate + ". TS Layers: " + params.temporalLayers +
+ ". Key frame:" + syncFrameInterval * params.frameRate +
+ ". Force keyFrame: " + params.syncForceFrameInterval);
+ Log.d(TAG, " Format: " + format[i]);
+ Log.d(TAG, " Output ivf:" + params.outputIvfFilename);
+
+ // Create encoder
+ codec[i] = new MediaEncoderAsync();
+ codec[i].createCodec(i, properties.codecName, format[i],
+ params.timeoutDequeue, params.runInLooperThread);
+ codecProperties[i] = new CodecProperties(properties.codecName, properties.colorFormat);
+
+ inputConsumed[i] = true;
+ ++numEncoders;
+ }
+ if (numEncoders == 0) {
+ Log.i(TAG, "no suitable encoders found for any of the streams");
+ return null;
+ }
+
+ while (!sawOutputEOSTotal) {
+ // Feed input buffer to all encoders
+ for (int i = 0; i < numEncoders; i++) {
+ bufferConsumed[i] = false;
+ if (consumedInputEOS[i]) {
+ continue;
+ }
+
+ EncoderOutputStreamParameters params = encodingParams.get(i);
+ // Read new input buffers - if previous input was consumed and no EOS
+ if (inputConsumed[i] && !sawInputEOS[i]) {
+ int bytesRead = yuvStream[i].read(srcFrame[i]);
+
+ // Check EOS
+ if (params.frameCount > 0 && inputFrameIndex[i] >= params.frameCount) {
+ sawInputEOS[i] = true;
+ Log.d(TAG, "---Enc" + i +
+ ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
+ }
+
+ if (!sawInputEOS[i] && bytesRead == -1) {
+ if (params.frameCount == 0) {
+ sawInputEOS[i] = true;
+ Log.d(TAG, "---Enc" + i +
+ ". Sending EOS empty frame for frame # " + inputFrameIndex[i]);
+ } else {
+ yuvStream[i].close();
+ yuvStream[i] = new FileInputStream(params.scaledYuvFilename);
+ bytesRead = yuvStream[i].read(srcFrame[i]);
+ }
+ }
+
+ // Convert YUV420 to NV12 if necessary
+ if (codecProperties[i].colorFormat !=
+ CodecCapabilities.COLOR_FormatYUV420Planar) {
+ srcFrame[i] =
+ YUV420ToNV(params.frameWidth, params.frameHeight, srcFrame[i]);
+ }
+ }
+
+ inputConsumed[i] = codec[i].feedInput(srcFrame[i], sawInputEOS[i]);
+ if (inputConsumed[i]) {
+ inputFrameIndex[i]++;
+ consumedInputEOS[i] = sawInputEOS[i];
+ bufferConsumed[i] = true;
+ }
+
+ }
+
+ // Get output from all encoders
+ for (int i = 0; i < numEncoders; i++) {
+ if (sawOutputEOS[i]) {
+ continue;
+ }
+
+ MediaEncoderOutput out = codec[i].getOutput();
+ if (out.outputGenerated) {
+ bufferConsumed[i] = true;
+ // Detect output EOS
+ if ((out.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ Log.d(TAG, "----Enc" + i + ". Output EOS ");
+ sawOutputEOS[i] = true;
+ }
+
+ if (out.buffer.length > 0) {
+ // Save frame
+ ivf[i].writeFrame(out.buffer, out.outPresentationTimeUs);
+
+ // Update statistics - store presentation time delay in offset
+ long presentationTimeUsDelta = out.inPresentationTimeUs -
+ out.outPresentationTimeUs;
+ MediaCodec.BufferInfo bufferInfoCopy = new MediaCodec.BufferInfo();
+ bufferInfoCopy.set((int)presentationTimeUsDelta, out.buffer.length,
+ out.outPresentationTimeUs, out.flags);
+ bufferInfos.get(i).add(bufferInfoCopy);
+ }
+ }
+ }
+
+ // If codec is not ready to accept input/output - wait for buffer ready callback
+ bufferConsumedTotal = false;
+ for (boolean bufferConsumedCurrent : bufferConsumed) {
+ bufferConsumedTotal |= bufferConsumedCurrent;
+ }
+ if (!bufferConsumedTotal) {
+ // Pick the encoder to wait for
+ for (int i = 0; i < numEncoders; i++) {
+ if (!bufferConsumed[i] && !sawOutputEOS[i]) {
+ codec[i].waitForBufferEvent();
+ break;
+ }
+ }
+ }
+
+ // Check if EOS happened for all encoders
+ sawOutputEOSTotal = true;
+ for (boolean sawOutputEOSStream : sawOutputEOS) {
+ sawOutputEOSTotal &= sawOutputEOSStream;
+ }
+ }
+
+ for (int i = 0; i < numEncoders; i++) {
+ codec[i].deleteCodec();
+ ivf[i].close();
+ yuvStream[i].close();
+ if (yuvScaled[i] != null) {
+ yuvScaled[i].close();
+ }
+ }
+
+ return bufferInfos;
+ }
+
+ /**
+ * Some encoding statistics.
+ */
+ protected class VpxEncodingStatistics {
+ VpxEncodingStatistics() {
+ mBitrates = new ArrayList<Integer>();
+ mFrames = new ArrayList<Integer>();
+ mKeyFrames = new ArrayList<Integer>();
+ mMinimumKeyFrameInterval = Integer.MAX_VALUE;
+ }
+
+ public ArrayList<Integer> mBitrates;// Bitrate values for each second of the encoded stream.
+ public ArrayList<Integer> mFrames; // Number of frames in each second of the encoded stream.
+ public int mAverageBitrate; // Average stream bitrate.
+ public ArrayList<Integer> mKeyFrames;// Stores the position of key frames in a stream.
+ public int mAverageKeyFrameInterval; // Average key frame interval.
+ public int mMaximumKeyFrameInterval; // Maximum key frame interval.
+ public int mMinimumKeyFrameInterval; // Minimum key frame interval.
+ }
+
+ /**
+ * Calculates average bitrate and key frame interval for the encoded streams.
+ * Output mBitrates field will contain bitrate values for every second
+ * of the encoded stream.
+ * Average stream bitrate will be stored in mAverageBitrate field.
+ * mKeyFrames array will contain the position of key frames in the encoded stream and
+ * mKeyFrameInterval - average key frame interval.
+ */
+ protected VpxEncodingStatistics computeEncodingStatistics(int encoderId,
+ ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
+ VpxEncodingStatistics statistics = new VpxEncodingStatistics();
+
+ int totalSize = 0;
+ int frames = 0;
+ int framesPerSecond = 0;
+ int totalFrameSizePerSecond = 0;
+ int maxFrameSize = 0;
+ int currentSecond;
+ int nextSecond = 0;
+ String keyFrameList = " IFrame List: ";
+ String bitrateList = " Bitrate list: ";
+ String framesList = " FPS list: ";
+
+
+ for (int j = 0; j < bufferInfos.size(); j++) {
+ MediaCodec.BufferInfo info = bufferInfos.get(j);
+ currentSecond = (int)(info.presentationTimeUs / 1000000);
+ boolean lastFrame = (j == bufferInfos.size() - 1);
+ if (!lastFrame) {
+ nextSecond = (int)(bufferInfos.get(j+1).presentationTimeUs / 1000000);
+ }
+
+ totalSize += info.size;
+ totalFrameSizePerSecond += info.size;
+ maxFrameSize = Math.max(maxFrameSize, info.size);
+ framesPerSecond++;
+ frames++;
+
+ // Update the bitrate statistics if the next frame will
+ // be for the next second
+ if (lastFrame || nextSecond > currentSecond) {
+ int currentBitrate = totalFrameSizePerSecond * 8;
+ bitrateList += (currentBitrate + " ");
+ framesList += (framesPerSecond + " ");
+ statistics.mBitrates.add(currentBitrate);
+ statistics.mFrames.add(framesPerSecond);
+ totalFrameSizePerSecond = 0;
+ framesPerSecond = 0;
+ }
+
+ // Update key frame statistics.
+ if ((info.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0) {
+ statistics.mKeyFrames.add(j);
+ keyFrameList += (j + " ");
+ }
+ }
+ int duration = (int)(bufferInfos.get(bufferInfos.size() - 1).presentationTimeUs / 1000);
+ duration = (duration + 500) / 1000;
+ statistics.mAverageBitrate = (int)(((long)totalSize * 8) / duration);
+ Log.d(TAG, "Statistics for encoder # " + encoderId);
+ // Calculate average key frame interval in frames.
+ int keyFrames = statistics.mKeyFrames.size();
+ if (keyFrames > 1) {
+ statistics.mAverageKeyFrameInterval =
+ statistics.mKeyFrames.get(keyFrames - 1) - statistics.mKeyFrames.get(0);
+ statistics.mAverageKeyFrameInterval =
+ Math.round((float)statistics.mAverageKeyFrameInterval / (keyFrames - 1));
+ for (int j = 1; j < keyFrames; j++) {
+ int keyFrameInterval =
+ statistics.mKeyFrames.get(j) - statistics.mKeyFrames.get(j - 1);
+ statistics.mMaximumKeyFrameInterval =
+ Math.max(statistics.mMaximumKeyFrameInterval, keyFrameInterval);
+ statistics.mMinimumKeyFrameInterval =
+ Math.min(statistics.mMinimumKeyFrameInterval, keyFrameInterval);
+ }
+ Log.d(TAG, " Key frame intervals: Max: " + statistics.mMaximumKeyFrameInterval +
+ ". Min: " + statistics.mMinimumKeyFrameInterval +
+ ". Avg: " + statistics.mAverageKeyFrameInterval);
+ }
+ Log.d(TAG, " Frames: " + frames + ". Duration: " + duration +
+ ". Total size: " + totalSize + ". Key frames: " + keyFrames);
+ Log.d(TAG, keyFrameList);
+ Log.d(TAG, bitrateList);
+ Log.d(TAG, framesList);
+ Log.d(TAG, " Bitrate average: " + statistics.mAverageBitrate);
+ Log.d(TAG, " Maximum frame size: " + maxFrameSize);
+
+ return statistics;
+ }
+
+ protected VpxEncodingStatistics computeEncodingStatistics(
+ ArrayList<MediaCodec.BufferInfo> bufferInfos ) {
+ return computeEncodingStatistics(0, bufferInfos);
+ }
+
+ protected ArrayList<VpxEncodingStatistics> computeSimulcastEncodingStatistics(
+ ArrayList<ArrayList<MediaCodec.BufferInfo>> bufferInfos) {
+ int numCodecs = bufferInfos.size();
+ ArrayList<VpxEncodingStatistics> statistics = new ArrayList<VpxEncodingStatistics>();
+
+ for (int i = 0; i < numCodecs; i++) {
+ VpxEncodingStatistics currentStatistics =
+ computeEncodingStatistics(i, bufferInfos.get(i));
+ statistics.add(currentStatistics);
+ }
+ return statistics;
+ }
+
+ /**
+ * Calculates maximum latency for encoder/decoder based on buffer info array
+ * generated either by encoder or decoder.
+ */
+ protected int maxPresentationTimeDifference(ArrayList<MediaCodec.BufferInfo> bufferInfos) {
+ int maxValue = 0;
+ for (MediaCodec.BufferInfo bufferInfo : bufferInfos) {
+ maxValue = Math.max(maxValue, bufferInfo.offset);
+ }
+ maxValue = (maxValue + 500) / 1000; // mcs -> ms
+ return maxValue;
+ }
+
+ /**
+ * Decoding PSNR statistics.
+ */
+ protected class VpxDecodingStatistics {
+ VpxDecodingStatistics() {
+ mMinimumPSNR = Integer.MAX_VALUE;
+ }
+ public double mAveragePSNR;
+ public double mMinimumPSNR;
+ }
+
+ /**
+ * Calculates PSNR value between two video frames.
+ */
+ private double computePSNR(byte[] data0, byte[] data1) {
+ long squareError = 0;
+ assertTrue(data0.length == data1.length);
+ int length = data0.length;
+ for (int i = 0 ; i < length; i++) {
+ int diff = ((int)data0[i] & 0xff) - ((int)data1[i] & 0xff);
+ squareError += diff * diff;
+ }
+ double meanSquareError = (double)squareError / length;
+ double psnr = 10 * Math.log10((double)255 * 255 / meanSquareError);
+ return psnr;
+ }
+
+ /**
+ * Calculates average and minimum PSNR values between
+ * set of reference and decoded video frames.
+ * Runs PSNR calculation for the full duration of the decoded data.
+ */
+ protected VpxDecodingStatistics computeDecodingStatistics(
+ String referenceYuvFilename,
+ int referenceYuvRawId,
+ String decodedYuvFilename,
+ int width,
+ int height) throws Exception {
+ VpxDecodingStatistics statistics = new VpxDecodingStatistics();
+ InputStream referenceStream =
+ OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
+ InputStream decodedStream = new FileInputStream(decodedYuvFilename);
+
+ int ySize = width * height;
+ int uvSize = width * height / 4;
+ byte[] yRef = new byte[ySize];
+ byte[] yDec = new byte[ySize];
+ byte[] uvRef = new byte[uvSize];
+ byte[] uvDec = new byte[uvSize];
+
+ int frames = 0;
+ double averageYPSNR = 0;
+ double averageUPSNR = 0;
+ double averageVPSNR = 0;
+ double minimumYPSNR = Integer.MAX_VALUE;
+ double minimumUPSNR = Integer.MAX_VALUE;
+ double minimumVPSNR = Integer.MAX_VALUE;
+ int minimumPSNRFrameIndex = 0;
+
+ while (true) {
+ // Calculate Y PSNR.
+ int bytesReadRef = referenceStream.read(yRef);
+ int bytesReadDec = decodedStream.read(yDec);
+ if (bytesReadDec == -1) {
+ break;
+ }
+ if (bytesReadRef == -1) {
+ // Reference file wrapping up
+ referenceStream.close();
+ referenceStream =
+ OpenFileOrResourceId(referenceYuvFilename, referenceYuvRawId);
+ bytesReadRef = referenceStream.read(yRef);
+ }
+ double curYPSNR = computePSNR(yRef, yDec);
+ averageYPSNR += curYPSNR;
+ minimumYPSNR = Math.min(minimumYPSNR, curYPSNR);
+ double curMinimumPSNR = curYPSNR;
+
+ // Calculate U PSNR.
+ bytesReadRef = referenceStream.read(uvRef);
+ bytesReadDec = decodedStream.read(uvDec);
+ double curUPSNR = computePSNR(uvRef, uvDec);
+ averageUPSNR += curUPSNR;
+ minimumUPSNR = Math.min(minimumUPSNR, curUPSNR);
+ curMinimumPSNR = Math.min(curMinimumPSNR, curUPSNR);
+
+ // Calculate V PSNR.
+ bytesReadRef = referenceStream.read(uvRef);
+ bytesReadDec = decodedStream.read(uvDec);
+ double curVPSNR = computePSNR(uvRef, uvDec);
+ averageVPSNR += curVPSNR;
+ minimumVPSNR = Math.min(minimumVPSNR, curVPSNR);
+ curMinimumPSNR = Math.min(curMinimumPSNR, curVPSNR);
+
+ // Frame index for minimum PSNR value - help to detect possible distortions
+ if (curMinimumPSNR < statistics.mMinimumPSNR) {
+ statistics.mMinimumPSNR = curMinimumPSNR;
+ minimumPSNRFrameIndex = frames;
+ }
+
+ String logStr = String.format(Locale.US, "PSNR #%d: Y: %.2f. U: %.2f. V: %.2f",
+ frames, curYPSNR, curUPSNR, curVPSNR);
+ Log.v(TAG, logStr);
+
+ frames++;
+ }
+
+ averageYPSNR /= frames;
+ averageUPSNR /= frames;
+ averageVPSNR /= frames;
+ statistics.mAveragePSNR = (4 * averageYPSNR + averageUPSNR + averageVPSNR) / 6;
+
+ Log.d(TAG, "PSNR statistics for " + frames + " frames.");
+ String logStr = String.format(Locale.US,
+ "Average PSNR: Y: %.1f. U: %.1f. V: %.1f. Average: %.1f",
+ averageYPSNR, averageUPSNR, averageVPSNR, statistics.mAveragePSNR);
+ Log.d(TAG, logStr);
+ logStr = String.format(Locale.US,
+ "Minimum PSNR: Y: %.1f. U: %.1f. V: %.1f. Overall: %.1f at frame %d",
+ minimumYPSNR, minimumUPSNR, minimumVPSNR,
+ statistics.mMinimumPSNR, minimumPSNRFrameIndex);
+ Log.d(TAG, logStr);
+
+ referenceStream.close();
+ decodedStream.close();
+ return statistics;
+ }
+}
+
diff --git a/tests/tests/media/src/android/media/cts/VpxEncoderTest.java b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
new file mode 100644
index 0000000..0e9c940
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.util.Log;
+import android.media.cts.R;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Verification test for vp8/vp9 encoder and decoder.
+ *
+ * A raw yv12 stream is encoded at various settings and written to an IVF
+ * file. Encoded stream bitrate and key frame interval are checked against target values.
+ * The stream is later decoded by vp8/vp9 decoder to verify frames are decodable and to
+ * calculate PSNR values for various bitrates.
+ */
+public class VpxEncoderTest extends VpxCodecTestBase {
+
+ private static final String ENCODED_IVF_BASE = "football";
+ private static final String INPUT_YUV = null;
+ private static final String OUTPUT_YUV = SDCARD_DIR + File.separator +
+ ENCODED_IVF_BASE + "_out.yuv";
+
+ // YUV stream properties.
+ private static final int WIDTH = 320;
+ private static final int HEIGHT = 240;
+ private static final int FPS = 30;
+ // Default encoding bitrate.
+ private static final int BITRATE = 400000;
+ // Default encoding bitrate mode
+ private static final int BITRATE_MODE = VIDEO_ControlRateVariable;
+ // List of bitrates used in quality and basic bitrate tests.
+ private static final int[] TEST_BITRATES_SET = { 300000, 500000, 700000, 900000 };
+ // Maximum allowed bitrate variation from the target value.
+ private static final double MAX_BITRATE_VARIATION = 0.2;
+ // Average PSNR values for reference Google VPx codec for the above bitrates.
+ private static final double[] REFERENCE_AVERAGE_PSNR = { 33.1, 35.2, 36.6, 37.8 };
+ // Minimum PSNR values for reference Google VPx codec for the above bitrates.
+ private static final double[] REFERENCE_MINIMUM_PSNR = { 25.9, 27.5, 28.4, 30.3 };
+ // Maximum allowed average PSNR difference of encoder comparing to reference Google encoder.
+ private static final double MAX_AVERAGE_PSNR_DIFFERENCE = 2;
+ // Maximum allowed minimum PSNR difference of encoder comparing to reference Google encoder.
+ private static final double MAX_MINIMUM_PSNR_DIFFERENCE = 4;
+ // Maximum allowed average PSNR difference of the encoder running in a looper thread with 0 ms
+ // buffer dequeue timeout comparing to the encoder running in a callee's thread with 100 ms
+ // buffer dequeue timeout.
+ private static final double MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE = 0.5;
+ // Maximum allowed minimum PSNR difference of the encoder running in a looper thread
+ // comparing to the encoder running in a callee's thread.
+ private static final double MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE = 2;
+ // Maximum allowed average key frame interval variation from the target value.
+ private static final int MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION = 1;
+ // Maximum allowed key frame interval variation from the target value.
+ private static final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
+
+ /**
+ * A basic test for VPx encoder.
+ *
+ * Encodes 9 seconds of raw stream with default configuration options,
+ * and then decodes it to verify the bitstream.
+ * Also checks the average bitrate is within MAX_BITRATE_VARIATION of the target value.
+ */
+ private void internalTestBasic(String codecMimeType) throws Exception {
+ int encodeSeconds = 9;
+ boolean skipped = true;
+
+ for (int targetBitrate : TEST_BITRATES_SET) {
+ EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ BITRATE_MODE,
+ targetBitrate,
+ true);
+ ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+ if (bufInfo == null) {
+ continue;
+ }
+ skipped = false;
+
+ VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+
+ assertEquals("Stream bitrate " + statistics.mAverageBitrate +
+ " is different from the target " + targetBitrate,
+ targetBitrate, statistics.mAverageBitrate,
+ MAX_BITRATE_VARIATION * targetBitrate);
+
+ decode(params.outputIvfFilename, null, codecMimeType, FPS, params.forceGoogleEncoder);
+ }
+
+ if (skipped) {
+ Log.i(TAG, "SKIPPING testBasic(): codec is not supported");
+ }
+ }
+
+ /**
+ * Asynchronous encoding test for VPx encoder.
+ *
+ * Encodes 9 seconds of raw stream using synchronous and asynchronous calls.
+ * Checks the PSNR difference between the encoded and decoded output and reference yuv input
+ * does not change much for two different ways of the encoder call.
+ */
+ private void internalTestAsyncEncoding(String codecMimeType) throws Exception {
+ int encodeSeconds = 9;
+
+ // First test the encoder running in a looper thread with buffer callbacks enabled.
+ boolean syncEncoding = false;
+ EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ BITRATE_MODE,
+ BITRATE,
+ syncEncoding);
+ ArrayList<MediaCodec.BufferInfo> bufInfos = encodeAsync(params);
+ if (bufInfos == null) {
+ Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
+ return;
+ }
+ computeEncodingStatistics(bufInfos);
+ decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+ VpxDecodingStatistics statisticsAsync = computeDecodingStatistics(
+ params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
+ params.frameWidth, params.frameHeight);
+
+
+ // Test the encoder running in a callee's thread.
+ syncEncoding = true;
+ params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ BITRATE_MODE,
+ BITRATE,
+ syncEncoding);
+ bufInfos = encode(params);
+ if (bufInfos == null) {
+ Log.i(TAG, "SKIPPING testAsyncEncoding(): no suitable encoder found");
+ return;
+ }
+ computeEncodingStatistics(bufInfos);
+ decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+ VpxDecodingStatistics statisticsSync = computeDecodingStatistics(
+ params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
+ params.frameWidth, params.frameHeight);
+
+ // Check PSNR difference.
+ Log.d(TAG, "PSNR Average: Async: " + statisticsAsync.mAveragePSNR +
+ ". Sync: " + statisticsSync.mAveragePSNR);
+ Log.d(TAG, "PSNR Minimum: Async: " + statisticsAsync.mMinimumPSNR +
+ ". Sync: " + statisticsSync.mMinimumPSNR);
+ if ((Math.abs(statisticsAsync.mAveragePSNR - statisticsSync.mAveragePSNR) >
+ MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE) ||
+ (Math.abs(statisticsAsync.mMinimumPSNR - statisticsSync.mMinimumPSNR) >
+ MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE)) {
+ throw new RuntimeException("Difference between PSNRs for async and sync encoders");
+ }
+ }
+
+ /**
+ * Check if MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME is honored.
+ *
+ * Encodes 9 seconds of raw stream and requests a sync frame every second (30 frames).
+ * The test does not verify the output stream.
+ */
+ private void internalTestSyncFrame(String codecMimeType) throws Exception {
+ int encodeSeconds = 9;
+
+ EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ BITRATE_MODE,
+ BITRATE,
+ true);
+ params.syncFrameInterval = encodeSeconds * FPS;
+ params.syncForceFrameInterval = FPS;
+ ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+ if (bufInfo == null) {
+ Log.i(TAG, "SKIPPING testSyncFrame(): no suitable encoder found");
+ return;
+ }
+
+ VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+
+ // First check if we got expected number of key frames.
+ int actualKeyFrames = statistics.mKeyFrames.size();
+ if (actualKeyFrames != encodeSeconds) {
+ throw new RuntimeException("Number of key frames " + actualKeyFrames +
+ " is different from the expected " + encodeSeconds);
+ }
+
+ // Check key frame intervals:
+ // Average value should be within +/- 1 frame of the target value,
+ // maximum value should not be greater than target value + 3,
+ // and minimum value should not be less that target value - 3.
+ if (Math.abs(statistics.mAverageKeyFrameInterval - FPS) >
+ MAX_AVERAGE_KEYFRAME_INTERVAL_VARIATION ||
+ (statistics.mMaximumKeyFrameInterval - FPS > MAX_KEYFRAME_INTERVAL_VARIATION) ||
+ (FPS - statistics.mMinimumKeyFrameInterval > MAX_KEYFRAME_INTERVAL_VARIATION)) {
+ throw new RuntimeException(
+ "Key frame intervals are different from the expected " + FPS);
+ }
+ }
+
+ /**
+ * Check if MediaCodec.PARAMETER_KEY_VIDEO_BITRATE is honored.
+ *
+ * Run the the encoder for 12 seconds. Request changes to the
+ * bitrate after 6 seconds and ensure the encoder responds.
+ */
+ private void internalTestDynamicBitrateChange(String codecMimeType) throws Exception {
+ int encodeSeconds = 12; // Encoding sequence duration in seconds.
+ int[] bitrateTargetValues = { 400000, 800000 }; // List of bitrates to test.
+
+ EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ BITRATE_MODE,
+ bitrateTargetValues[0],
+ true);
+
+ // Number of seconds for each bitrate
+ int stepSeconds = encodeSeconds / bitrateTargetValues.length;
+ // Fill the bitrates values.
+ params.bitrateSet = new int[encodeSeconds * FPS];
+ for (int i = 0; i < bitrateTargetValues.length ; i++) {
+ Arrays.fill(params.bitrateSet,
+ i * encodeSeconds * FPS / bitrateTargetValues.length,
+ (i + 1) * encodeSeconds * FPS / bitrateTargetValues.length,
+ bitrateTargetValues[i]);
+ }
+
+ ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+ if (bufInfo == null) {
+ Log.i(TAG, "SKIPPING testDynamicBitrateChange(): no suitable encoder found");
+ return;
+ }
+
+ VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+
+ // Calculate actual average bitrates for every [stepSeconds] second.
+ int[] bitrateActualValues = new int[bitrateTargetValues.length];
+ for (int i = 0; i < bitrateTargetValues.length ; i++) {
+ bitrateActualValues[i] = 0;
+ for (int j = i * stepSeconds; j < (i + 1) * stepSeconds; j++) {
+ bitrateActualValues[i] += statistics.mBitrates.get(j);
+ }
+ bitrateActualValues[i] /= stepSeconds;
+ Log.d(TAG, "Actual bitrate for interval #" + i + " : " + bitrateActualValues[i] +
+ ". Target: " + bitrateTargetValues[i]);
+
+ // Compare actual bitrate values to make sure at least same increasing/decreasing
+ // order as the target bitrate values.
+ for (int j = 0; j < i; j++) {
+ long differenceTarget = bitrateTargetValues[i] - bitrateTargetValues[j];
+ long differenceActual = bitrateActualValues[i] - bitrateActualValues[j];
+ if (differenceTarget * differenceActual < 0) {
+ throw new RuntimeException("Target bitrates: " +
+ bitrateTargetValues[j] + " , " + bitrateTargetValues[i] +
+ ". Actual bitrates: "
+ + bitrateActualValues[j] + " , " + bitrateActualValues[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if encoder and decoder can run simultaneously on different threads.
+ *
+ * Encodes and decodes 9 seconds of raw stream sequentially in CBR mode,
+ * and then run parallel encoding and decoding of the same streams.
+ * Compares average bitrate and PSNR for sequential and parallel runs.
+ */
+ private void internalTestParallelEncodingAndDecoding(String codecMimeType) throws Exception {
+ // check for encoder up front, as by the time we detect lack of
+ // encoder support, we may have already started decoding.
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaFormat format = MediaFormat.createVideoFormat(codecMimeType, WIDTH, HEIGHT);
+ if (mcl.findEncoderForFormat(format) == null) {
+ Log.i(TAG, "SKIPPING testParallelEncodingAndDecoding(): no suitable encoder found");
+ return;
+ }
+
+ int encodeSeconds = 9;
+ final int[] bitrate = new int[1];
+ final double[] psnr = new double[1];
+ final Exception[] exceptionEncoder = new Exception[1];
+ final Exception[] exceptionDecoder = new Exception[1];
+ final EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ VIDEO_ControlRateConstant,
+ BITRATE,
+ true);
+ final String inputIvfFilename = params.outputIvfFilename;
+
+ Runnable runEncoder = new Runnable() {
+ public void run() {
+ try {
+ ArrayList<MediaCodec.BufferInfo> bufInfo = encode(params);
+ VpxEncodingStatistics statistics = computeEncodingStatistics(bufInfo);
+ bitrate[0] = statistics.mAverageBitrate;
+ } catch (Exception e) {
+ Log.e(TAG, "Encoder error: " + e.toString());
+ exceptionEncoder[0] = e;
+ }
+ }
+ };
+ Runnable runDecoder = new Runnable() {
+ public void run() {
+ try {
+ decode(inputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+ VpxDecodingStatistics statistics = computeDecodingStatistics(
+ params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
+ params.frameWidth, params.frameHeight);
+ psnr[0] = statistics.mAveragePSNR;
+ } catch (Exception e) {
+ Log.e(TAG, "Decoder error: " + e.toString());
+ exceptionDecoder[0] = e;
+ }
+ }
+ };
+
+ // Sequential encoding and decoding.
+ runEncoder.run();
+ if (exceptionEncoder[0] != null) {
+ throw exceptionEncoder[0];
+ }
+ int referenceBitrate = bitrate[0];
+ runDecoder.run();
+ if (exceptionDecoder[0] != null) {
+ throw exceptionDecoder[0];
+ }
+ double referencePsnr = psnr[0];
+
+ // Parallel encoding and decoding.
+ params.outputIvfFilename = SDCARD_DIR + File.separator + ENCODED_IVF_BASE + "_copy.ivf";
+ Thread threadEncoder = new Thread(runEncoder);
+ Thread threadDecoder = new Thread(runDecoder);
+ threadEncoder.start();
+ threadDecoder.start();
+ threadEncoder.join();
+ threadDecoder.join();
+ if (exceptionEncoder[0] != null) {
+ throw exceptionEncoder[0];
+ }
+ if (exceptionDecoder[0] != null) {
+ throw exceptionDecoder[0];
+ }
+
+ // Compare bitrates and PSNRs for sequential and parallel cases.
+ Log.d(TAG, "Sequential bitrate: " + referenceBitrate + ". PSNR: " + referencePsnr);
+ Log.d(TAG, "Parallel bitrate: " + bitrate[0] + ". PSNR: " + psnr[0]);
+ assertEquals("Bitrate for sequenatial encoding" + referenceBitrate +
+ " is different from parallel encoding " + bitrate[0],
+ referenceBitrate, bitrate[0], MAX_BITRATE_VARIATION * referenceBitrate);
+ assertEquals("PSNR for sequenatial encoding" + referencePsnr +
+ " is different from parallel encoding " + psnr[0],
+ referencePsnr, psnr[0], MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE);
+ }
+
+
+ /**
+ * Check the encoder quality for various bitrates by calculating PSNR
+ *
+ * Run the the encoder for 9 seconds for each bitrate and calculate PSNR
+ * for each encoded stream.
+ * Video streams with higher bitrates should have higher PSNRs.
+ * Also compares average and minimum PSNR of codec with PSNR values of reference Google codec.
+ */
+ private void internalTestEncoderQuality(String codecMimeType) throws Exception {
+ int encodeSeconds = 9; // Encoding sequence duration in seconds for each bitrate.
+ double[] psnrPlatformCodecAverage = new double[TEST_BITRATES_SET.length];
+ double[] psnrPlatformCodecMin = new double[TEST_BITRATES_SET.length];
+ boolean[] completed = new boolean[TEST_BITRATES_SET.length];
+ boolean skipped = true;
+
+ // Run platform specific encoder for different bitrates
+ // and compare PSNR of codec with PSNR of reference Google codec.
+ for (int i = 0; i < TEST_BITRATES_SET.length; i++) {
+ EncoderOutputStreamParameters params = getDefaultEncodingParameters(
+ INPUT_YUV,
+ ENCODED_IVF_BASE,
+ codecMimeType,
+ encodeSeconds,
+ WIDTH,
+ HEIGHT,
+ FPS,
+ BITRATE_MODE,
+ TEST_BITRATES_SET[i],
+ true);
+ if (encode(params) == null) {
+ // parameters not supported, try other bitrates
+ completed[i] = false;
+ continue;
+ }
+ completed[i] = true;
+ skipped = false;
+
+ decode(params.outputIvfFilename, OUTPUT_YUV, codecMimeType, FPS, params.forceGoogleEncoder);
+ VpxDecodingStatistics statistics = computeDecodingStatistics(
+ params.inputYuvFilename, R.raw.football_qvga, OUTPUT_YUV,
+ params.frameWidth, params.frameHeight);
+ psnrPlatformCodecAverage[i] = statistics.mAveragePSNR;
+ psnrPlatformCodecMin[i] = statistics.mMinimumPSNR;
+ }
+
+ if (skipped) {
+ Log.i(TAG, "SKIPPING testEncoderQuality(): no bitrates supported");
+ return;
+ }
+
+ // First do a sanity check - higher bitrates should results in higher PSNR.
+ for (int i = 1; i < TEST_BITRATES_SET.length ; i++) {
+ if (!completed[i]) {
+ continue;
+ }
+ for (int j = 0; j < i; j++) {
+ if (!completed[j]) {
+ continue;
+ }
+ double differenceBitrate = TEST_BITRATES_SET[i] - TEST_BITRATES_SET[j];
+ double differencePSNR = psnrPlatformCodecAverage[i] - psnrPlatformCodecAverage[j];
+ if (differenceBitrate * differencePSNR < 0) {
+ throw new RuntimeException("Target bitrates: " +
+ TEST_BITRATES_SET[j] + ", " + TEST_BITRATES_SET[i] +
+ ". Actual PSNRs: "
+ + psnrPlatformCodecAverage[j] + ", " + psnrPlatformCodecAverage[i]);
+ }
+ }
+ }
+
+ // Then compare average and minimum PSNR of platform codec with reference Google codec -
+ // average PSNR for platform codec should be no more than 2 dB less than reference PSNR
+ // and minumum PSNR - no more than 4 dB less than reference minimum PSNR.
+ // These PSNR difference numbers are arbitrary for now, will need further estimation
+ // when more devices with HW VP8 codec will appear.
+ for (int i = 0; i < TEST_BITRATES_SET.length ; i++) {
+ if (!completed[i]) {
+ continue;
+ }
+
+ Log.d(TAG, "Bitrate " + TEST_BITRATES_SET[i]);
+ Log.d(TAG, "Reference: Average: " + REFERENCE_AVERAGE_PSNR[i] + ". Minimum: " +
+ REFERENCE_MINIMUM_PSNR[i]);
+ Log.d(TAG, "Platform: Average: " + psnrPlatformCodecAverage[i] + ". Minimum: " +
+ psnrPlatformCodecMin[i]);
+ if (psnrPlatformCodecAverage[i] < REFERENCE_AVERAGE_PSNR[i] -
+ MAX_AVERAGE_PSNR_DIFFERENCE) {
+ throw new RuntimeException("Low average PSNR " + psnrPlatformCodecAverage[i] +
+ " comparing to reference PSNR " + REFERENCE_AVERAGE_PSNR[i] +
+ " for bitrate " + TEST_BITRATES_SET[i]);
+ }
+ if (psnrPlatformCodecMin[i] < REFERENCE_MINIMUM_PSNR[i] -
+ MAX_MINIMUM_PSNR_DIFFERENCE) {
+ throw new RuntimeException("Low minimum PSNR " + psnrPlatformCodecMin[i] +
+ " comparing to reference PSNR " + REFERENCE_MINIMUM_PSNR[i] +
+ " for bitrate " + TEST_BITRATES_SET[i]);
+ }
+ }
+ }
+
+ public void testBasicVP8() throws Exception { internalTestBasic(VP8_MIME); }
+ public void testBasicVP9() throws Exception { internalTestBasic(VP9_MIME); }
+
+ public void testAsyncEncodingVP8() throws Exception { internalTestAsyncEncoding(VP8_MIME); }
+ public void testAsyncEncodingVP9() throws Exception { internalTestAsyncEncoding(VP9_MIME); }
+
+ public void testSyncFrameVP8() throws Exception { internalTestSyncFrame(VP8_MIME); }
+ public void testSyncFrameVP9() throws Exception { internalTestSyncFrame(VP9_MIME); }
+
+ public void testDynamicBitrateChangeVP8() throws Exception {
+ internalTestDynamicBitrateChange(VP8_MIME);
+ }
+ public void testDynamicBitrateChangeVP9() throws Exception {
+ internalTestDynamicBitrateChange(VP9_MIME);
+ }
+
+ public void testParallelEncodingAndDecodingVP8() throws Exception {
+ internalTestParallelEncodingAndDecoding(VP8_MIME);
+ }
+ public void testParallelEncodingAndDecodingVP9() throws Exception {
+ internalTestParallelEncodingAndDecoding(VP9_MIME);
+ }
+
+ public void testEncoderQualityVP8() throws Exception { internalTestEncoderQuality(VP8_MIME); }
+ public void testEncoderQualityVP9() throws Exception { internalTestEncoderQuality(VP9_MIME); }
+
+}
+
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index bbee284..7ba9a5a 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -25,7 +25,7 @@
LOCAL_MULTILIB := both
LOCAL_STATIC_JAVA_LIBRARIES := \
- ctsdeviceutil ctstestrunner guava platform-test-annotations
+ ctsdeviceutil ctstestrunner guava platform-test-annotations android-support-test
LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libctsos_jni libnativehelper_compat_libc++
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index e01f386..b77f617 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -18,8 +18,8 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android" coreApp="true" android:sharedUserId="android.uid.system"
- android:sharedUserLabel="@string/android_system_label">
+ package="android" coreApp="true" android:sharedUserId="android.uid.system"
+ android:sharedUserLabel="@string/android_system_label">
<!-- ================================================ -->
<!-- Special broadcasts that only the system can send -->
@@ -138,49 +138,46 @@
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REPLY" />
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" />
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
- <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
<protected-broadcast
- android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
+ android:name="android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
+ android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+ android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+ android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+ android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+ android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
<protected-broadcast
- android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+ android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
<protected-broadcast
- android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+ android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+ android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
+ android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
<protected-broadcast
- android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
+ android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
<protected-broadcast
- android:name="android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED" />
- <protected-broadcast
- android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
<protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
<protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
@@ -192,7 +189,6 @@
<protected-broadcast android:name="android.btopp.intent.action.RETRY" />
<protected-broadcast android:name="android.btopp.intent.action.OPEN" />
<protected-broadcast android:name="android.btopp.intent.action.OPEN_INBOUND" />
- <protected-broadcast android:name="android.btopp.intent.action.TRANSFER_COMPLETE" />
<protected-broadcast android:name="com.android.bluetooth.pbap.authchall" />
<protected-broadcast android:name="com.android.bluetooth.pbap.userconfirmtimeout" />
<protected-broadcast android:name="com.android.bluetooth.pbap.authresponse" />
@@ -307,7 +303,7 @@
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
<protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
- <protected-broadcast android:name="com.android.server.ACTION_TRIGGER_IDLE" />
+ <protected-broadcast android:name="com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE" />
<protected-broadcast android:name="android.intent.action.HDMI_PLUGGED" />
@@ -324,11 +320,11 @@
<protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" />
<protected-broadcast
- android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
+ android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" />
<!-- Defined in RestrictionsManager -->
<protected-broadcast
- android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
+ android:name="android.intent.action.PERMISSION_RESPONSE_RECEIVED" />
<!-- Defined in RestrictionsManager -->
<protected-broadcast android:name="android.intent.action.REQUEST_PERMISSION" />
@@ -487,28 +483,28 @@
<!-- Used for runtime permissions related to contacts and profiles on this
device. -->
<permission-group android:name="android.permission-group.CONTACTS"
- android:icon="@drawable/perm_group_contacts"
- android:label="@string/permgrouplab_contacts"
- android:description="@string/permgroupdesc_contacts"
- android:priority="100" />
+ android:icon="@drawable/perm_group_contacts"
+ android:label="@string/permgrouplab_contacts"
+ android:description="@string/permgroupdesc_contacts"
+ android:priority="100" />
<!-- Allows an application to read the user's contacts data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CONTACTS"
- android:permissionGroup="android.permission-group.CONTACTS"
- android:label="@string/permlab_readContacts"
- android:description="@string/permdesc_readContacts"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CONTACTS"
+ android:label="@string/permlab_readContacts"
+ android:description="@string/permdesc_readContacts"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write the user's contacts data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CONTACTS"
- android:permissionGroup="android.permission-group.CONTACTS"
- android:label="@string/permlab_writeContacts"
- android:description="@string/permdesc_writeContacts"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CONTACTS"
+ android:label="@string/permlab_writeContacts"
+ android:description="@string/permdesc_writeContacts"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing user's calendar -->
@@ -517,28 +513,28 @@
<!-- Used for runtime permissions related to user's calendar. -->
<permission-group android:name="android.permission-group.CALENDAR"
- android:icon="@drawable/perm_group_calendar"
- android:label="@string/permgrouplab_calendar"
- android:description="@string/permgroupdesc_calendar"
- android:priority="200" />
+ android:icon="@drawable/perm_group_calendar"
+ android:label="@string/permgrouplab_calendar"
+ android:description="@string/permgroupdesc_calendar"
+ android:priority="200" />
<!-- Allows an application to read the user's calendar data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CALENDAR"
- android:permissionGroup="android.permission-group.CALENDAR"
- android:label="@string/permlab_readCalendar"
- android:description="@string/permdesc_readCalendar"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CALENDAR"
+ android:label="@string/permlab_readCalendar"
+ android:description="@string/permdesc_readCalendar"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write the user's calendar data.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CALENDAR"
- android:permissionGroup="android.permission-group.CALENDAR"
- android:label="@string/permlab_writeCalendar"
- android:description="@string/permdesc_writeCalendar"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CALENDAR"
+ android:label="@string/permlab_writeCalendar"
+ android:description="@string/permdesc_writeCalendar"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing and modifying user's SMS messages -->
@@ -547,56 +543,56 @@
<!-- Used for runtime permissions related to user's SMS messages. -->
<permission-group android:name="android.permission-group.SMS"
- android:icon="@drawable/perm_group_sms"
- android:label="@string/permgrouplab_sms"
- android:description="@string/permgroupdesc_sms"
- android:priority="300" />
+ android:icon="@drawable/perm_group_sms"
+ android:label="@string/permgrouplab_sms"
+ android:description="@string/permgroupdesc_sms"
+ android:priority="300" />
<!-- Allows an application to send SMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.SEND_SMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_sendSms"
- android:description="@string/permdesc_sendSms"
- android:permissionFlags="costsMoney"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_sendSms"
+ android:description="@string/permdesc_sendSms"
+ android:permissionFlags="costsMoney"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to receive SMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECEIVE_SMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_receiveSms"
- android:description="@string/permdesc_receiveSms"
- android:protectionLevel="dangerous"/>
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_receiveSms"
+ android:description="@string/permdesc_receiveSms"
+ android:protectionLevel="dangerous"/>
<!-- Allows an application to read SMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_SMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_readSms"
- android:description="@string/permdesc_readSms"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_readSms"
+ android:description="@string/permdesc_readSms"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to receive WAP push messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECEIVE_WAP_PUSH"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_receiveWapPush"
- android:description="@string/permdesc_receiveWapPush"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_receiveWapPush"
+ android:description="@string/permdesc_receiveWapPush"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to monitor incoming MMS messages.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECEIVE_MMS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_receiveMms"
- android:description="@string/permdesc_receiveMms"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_receiveMms"
+ android:description="@string/permdesc_receiveMms"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to read previously received cell broadcast
messages and to register a content observer to get notifications when
@@ -611,10 +607,10 @@
<p>Protection level: dangerous
@hide Pending API council approval -->
<permission android:name="android.permission.READ_CELL_BROADCASTS"
- android:permissionGroup="android.permission-group.SMS"
- android:label="@string/permlab_readCellBroadcasts"
- android:description="@string/permdesc_readCellBroadcasts"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SMS"
+ android:label="@string/permlab_readCellBroadcasts"
+ android:description="@string/permdesc_readCellBroadcasts"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing external storage -->
@@ -623,10 +619,10 @@
<!-- Used for runtime permissions related to the shared external storage. -->
<permission-group android:name="android.permission-group.STORAGE"
- android:icon="@drawable/perm_group_storage"
- android:label="@string/permgrouplab_storage"
- android:description="@string/permgroupdesc_storage"
- android:priority="900" />
+ android:icon="@drawable/perm_group_storage"
+ android:label="@string/permgrouplab_storage"
+ android:description="@string/permgroupdesc_storage"
+ android:priority="900" />
<!-- Allows an application to read from external storage.
<p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
@@ -651,10 +647,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_EXTERNAL_STORAGE"
- android:permissionGroup="android.permission-group.STORAGE"
- android:label="@string/permlab_sdcardRead"
- android:description="@string/permdesc_sdcardRead"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_sdcardRead"
+ android:description="@string/permdesc_sdcardRead"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write to external storage.
<p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -672,10 +668,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
- android:permissionGroup="android.permission-group.STORAGE"
- android:label="@string/permlab_sdcardWrite"
- android:description="@string/permdesc_sdcardWrite"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_sdcardWrite"
+ android:description="@string/permdesc_sdcardWrite"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device location -->
@@ -684,28 +680,28 @@
<!-- Used for permissions that allow accessing the device location. -->
<permission-group android:name="android.permission-group.LOCATION"
- android:icon="@drawable/perm_group_location"
- android:label="@string/permgrouplab_location"
- android:description="@string/permgroupdesc_location"
- android:priority="400" />
+ android:icon="@drawable/perm_group_location"
+ android:label="@string/permgrouplab_location"
+ android:description="@string/permgroupdesc_location"
+ android:priority="400" />
<!-- Allows an app to access precise location.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_FINE_LOCATION"
- android:permissionGroup="android.permission-group.LOCATION"
- android:label="@string/permlab_accessFineLocation"
- android:description="@string/permdesc_accessFineLocation"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.LOCATION"
+ android:label="@string/permlab_accessFineLocation"
+ android:description="@string/permdesc_accessFineLocation"
+ android:protectionLevel="dangerous" />
<!-- Allows an app to access approximate location.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_COARSE_LOCATION"
- android:permissionGroup="android.permission-group.LOCATION"
- android:label="@string/permlab_accessCoarseLocation"
- android:description="@string/permdesc_accessCoarseLocation"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.LOCATION"
+ android:label="@string/permlab_accessCoarseLocation"
+ android:description="@string/permdesc_accessCoarseLocation"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device telephony -->
@@ -714,10 +710,10 @@
<!-- Used for permissions that are associated telephony features. -->
<permission-group android:name="android.permission-group.PHONE"
- android:icon="@drawable/perm_group_phone_calls"
- android:label="@string/permgrouplab_phone"
- android:description="@string/permgroupdesc_phone"
- android:priority="500" />
+ android:icon="@drawable/perm_group_phone_calls"
+ android:label="@string/permgrouplab_phone"
+ android:description="@string/permgroupdesc_phone"
+ android:priority="500" />
<!-- Allows read only access to phone state, including the phone number of the device,
current cellular network information, the status of any ongoing calls, and a list of any
@@ -733,21 +729,21 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_PHONE_STATE"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readPhoneState"
- android:description="@string/permdesc_readPhoneState"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readPhoneState"
+ android:description="@string/permdesc_readPhoneState"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to initiate a phone call without going through
the Dialer user interface for the user to confirm the call.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.CALL_PHONE"
- android:permissionGroup="android.permission-group.PHONE"
- android:permissionFlags="costsMoney"
- android:label="@string/permlab_callPhone"
- android:description="@string/permdesc_callPhone"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:permissionFlags="costsMoney"
+ android:label="@string/permlab_callPhone"
+ android:description="@string/permdesc_callPhone"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to access the IMS call service: making and
modifying a call
@@ -755,10 +751,10 @@
@hide
-->
<permission android:name="android.permission.ACCESS_IMS_CALL_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_accessImsCallService"
- android:description="@string/permdesc_accessImsCallService"
- android:protectionLevel="signature|privileged" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_accessImsCallService"
+ android:description="@string/permdesc_accessImsCallService"
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to read the user's call log.
<p class="note"><strong>Note:</strong> If your app uses the
@@ -773,10 +769,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.READ_CALL_LOG"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_readCallLog"
- android:description="@string/permdesc_readCallLog"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readCallLog"
+ android:description="@string/permdesc_readCallLog"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write (but not read) the user's
call log data.
@@ -792,28 +788,28 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.WRITE_CALL_LOG"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_writeCallLog"
- android:description="@string/permdesc_writeCallLog"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_writeCallLog"
+ android:description="@string/permdesc_writeCallLog"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to add voicemails into the system.
<p>Protection level: dangerous
-->
<permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_addVoicemail"
- android:description="@string/permdesc_addVoicemail"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_addVoicemail"
+ android:description="@string/permdesc_addVoicemail"
+ android:protectionLevel="dangerous" />
<!-- Allows an application to use SIP service.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.USE_SIP"
- android:permissionGroup="android.permission-group.PHONE"
- android:description="@string/permdesc_use_sip"
- android:label="@string/permlab_use_sip"
- android:protectionLevel="dangerous"/>
+ android:permissionGroup="android.permission-group.PHONE"
+ android:description="@string/permdesc_use_sip"
+ android:label="@string/permlab_use_sip"
+ android:protectionLevel="dangerous"/>
<!-- Allows an application to see the number being dialed during an outgoing
call with the option to redirect the call to a different number or
@@ -821,10 +817,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_processOutgoingCalls"
- android:description="@string/permdesc_processOutgoingCalls"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_processOutgoingCalls"
+ android:description="@string/permdesc_processOutgoingCalls"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
@@ -835,19 +831,19 @@
microphone audio from the device. Note that phone calls also capture audio
but are in a separate (more visible) permission group. -->
<permission-group android:name="android.permission-group.MICROPHONE"
- android:icon="@drawable/perm_group_microphone"
- android:label="@string/permgrouplab_microphone"
- android:description="@string/permgroupdesc_microphone"
- android:priority="600" />
+ android:icon="@drawable/perm_group_microphone"
+ android:label="@string/permgrouplab_microphone"
+ android:description="@string/permgroupdesc_microphone"
+ android:priority="600" />
<!-- Allows an application to record audio.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.RECORD_AUDIO"
- android:permissionGroup="android.permission-group.MICROPHONE"
- android:label="@string/permlab_recordAudio"
- android:description="@string/permdesc_recordAudio"
- android:protectionLevel="dangerous"/>
+ android:permissionGroup="android.permission-group.MICROPHONE"
+ android:label="@string/permlab_recordAudio"
+ android:description="@string/permdesc_recordAudio"
+ android:protectionLevel="dangerous"/>
<!-- ====================================================================== -->
<!-- Permissions for accessing the UCE Service -->
@@ -857,15 +853,15 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="signatureOrSystem"/>
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="signatureOrSystem"/>
<!-- @hide Allows an application to Access UCE-OPTIONS.
<p>Protection level: dangerous
-->
<permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
- android:permissionGroup="android.permission-group.PHONE"
- android:protectionLevel="signatureOrSystem"/>
+ android:permissionGroup="android.permission-group.PHONE"
+ android:protectionLevel="signatureOrSystem"/>
@@ -877,10 +873,10 @@
<!-- Used for permissions that are associated with accessing
camera or capturing images/video from the device. -->
<permission-group android:name="android.permission-group.CAMERA"
- android:icon="@drawable/perm_group_camera"
- android:label="@string/permgrouplab_camera"
- android:description="@string/permgroupdesc_camera"
- android:priority="700" />
+ android:icon="@drawable/perm_group_camera"
+ android:label="@string/permgrouplab_camera"
+ android:description="@string/permgroupdesc_camera"
+ android:priority="700" />
<!-- Required to be able to access the camera device.
<p>This will automatically enforce the <a
@@ -892,10 +888,10 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.CAMERA"
- android:permissionGroup="android.permission-group.CAMERA"
- android:label="@string/permlab_camera"
- android:description="@string/permdesc_camera"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.CAMERA"
+ android:label="@string/permlab_camera"
+ android:description="@string/permdesc_camera"
+ android:protectionLevel="dangerous" />
<!-- ====================================================================== -->
@@ -906,28 +902,28 @@
<!-- Used for permissions that are associated with accessing
camera or capturing images/video from the device. -->
<permission-group android:name="android.permission-group.SENSORS"
- android:icon="@drawable/perm_group_sensors"
- android:label="@string/permgrouplab_sensors"
- android:description="@string/permgroupdesc_sensors"
- android:priority="800" />
+ android:icon="@drawable/perm_group_sensors"
+ android:label="@string/permgrouplab_sensors"
+ android:description="@string/permgroupdesc_sensors"
+ android:priority="800" />
<!-- Allows an application to access data from sensors that the user uses to
measure what is happening inside his/her body, such as heart rate.
<p>Protection level: dangerous -->
<permission android:name="android.permission.BODY_SENSORS"
- android:permissionGroup="android.permission-group.SENSORS"
- android:label="@string/permlab_bodySensors"
- android:description="@string/permdesc_bodySensors"
- android:protectionLevel="dangerous" />
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_bodySensors"
+ android:description="@string/permdesc_bodySensors"
+ android:protectionLevel="dangerous" />
<!-- Allows an app to use fingerprint hardware.
<p>Protection level: normal
-->
<permission android:name="android.permission.USE_FINGERPRINT"
- android:permissionGroup="android.permission-group.SENSORS"
- android:label="@string/permlab_useFingerprint"
- android:description="@string/permdesc_useFingerprint"
- android:protectionLevel="normal" />
+ android:permissionGroup="android.permission-group.SENSORS"
+ android:label="@string/permlab_useFingerprint"
+ android:description="@string/permdesc_useFingerprint"
+ android:protectionLevel="normal" />
<!-- ====================================================================== -->
<!-- REMOVED PERMISSIONS -->
@@ -935,78 +931,78 @@
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_PROFILE"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_PROFILE"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_SOCIAL_STREAM"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SOCIAL_STREAM"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.READ_USER_DICTIONARY"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_USER_DICTIONARY"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.WRITE_SMS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.MANAGE_ACCOUNTS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.USE_CREDENTIALS"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- @hide We need to keep this around for backwards compatibility -->
<permission android:name="android.permission.FLASHLIGHT"
- android:protectionLevel="normal"
- android:permissionFlags="removed"/>
+ android:protectionLevel="normal"
+ android:permissionFlags="removed"/>
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
@@ -1021,37 +1017,35 @@
to handle the respond-via-message action during incoming calls.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
- <p>Not for use by third-party applications.
- @hide -->
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to filter carrier specific sms.
@hide -->
<permission android:name="android.permission.CARRIER_FILTER_SMS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
to record or display them to the user.
- <p>Not for use by third-party applications.
- @hide -->
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
or perform processing on them. -->
<!-- @hide -->
<permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to execute contacts directory search.
This should only be used by ContactsProvider.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to modify cell broadcasts through the content provider.
<p>Not for use by third-party applications. -->
@@ -1067,9 +1061,9 @@
<p>Protection level: normal
-->
<permission android:name="com.android.alarm.permission.SET_ALARM"
- android:label="@string/permlab_setAlarm"
- android:description="@string/permdesc_setAlarm"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setAlarm"
+ android:description="@string/permdesc_setAlarm"
+ android:protectionLevel="normal" />
<!-- =============================================================== -->
<!-- Permissions for accessing the user voicemail -->
@@ -1080,13 +1074,13 @@
<p>Protection level: signature|privileged
-->
<permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to read voicemails in the system.
<p>Protection level: signature|privileged
-->
<permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ======================================= -->
<!-- Permissions for accessing location info -->
@@ -1097,26 +1091,26 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"
- android:label="@string/permlab_accessLocationExtraCommands"
- android:description="@string/permdesc_accessLocationExtraCommands"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_accessLocationExtraCommands"
+ android:description="@string/permdesc_accessLocationExtraCommands"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an application to install a location provider into the Location Manager.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
This should only be used by HDMI-CEC service.
-->
<permission android:name="android.permission.HDMI_CEC"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to use location features in hardware,
such as the geofencing api.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.LOCATION_HARDWARE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
<!-- @SystemApi Allows an application to create mock location providers for testing.
@@ -1124,7 +1118,7 @@
@hide
-->
<permission android:name="android.permission.ACCESS_MOCK_LOCATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ======================================= -->
<!-- Permissions for accessing networks -->
@@ -1135,73 +1129,73 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.INTERNET"
- android:description="@string/permdesc_createNetworkSockets"
- android:label="@string/permlab_createNetworkSockets"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_createNetworkSockets"
+ android:label="@string/permlab_createNetworkSockets"
+ android:protectionLevel="normal" />
<!-- Allows applications to access information about networks.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_NETWORK_STATE"
- android:description="@string/permdesc_accessNetworkState"
- android:label="@string/permlab_accessNetworkState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_accessNetworkState"
+ android:label="@string/permlab_accessNetworkState"
+ android:protectionLevel="normal" />
<!-- Allows applications to access information about Wi-Fi networks.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_WIFI_STATE"
- android:description="@string/permdesc_accessWifiState"
- android:label="@string/permlab_accessWifiState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_accessWifiState"
+ android:label="@string/permlab_accessWifiState"
+ android:protectionLevel="normal" />
<!-- Allows applications to change Wi-Fi connectivity state.
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_WIFI_STATE"
- android:description="@string/permdesc_changeWifiState"
- android:label="@string/permlab_changeWifiState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeWifiState"
+ android:label="@string/permlab_changeWifiState"
+ android:protectionLevel="normal" />
<!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_WIFI_CREDENTIAL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows applications to change tether state and run
tether carrier provisioning.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.TETHER_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allow system apps to receive broadcast
when a wifi network credential is changed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
by another application. Once reconfigured the original creator cannot make any further
modifications.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide -->
<permission android:name="android.permission.ACCESS_WIMAX_STATE"
- android:description="@string/permdesc_accessWimaxState"
- android:label="@string/permlab_accessWimaxState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_accessWimaxState"
+ android:label="@string/permlab_accessWimaxState"
+ android:protectionLevel="normal" />
<!-- @hide -->
<permission android:name="android.permission.CHANGE_WIMAX_STATE"
- android:description="@string/permdesc_changeWimaxState"
- android:label="@string/permlab_changeWimaxState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeWimaxState"
+ android:label="@string/permlab_changeWimaxState"
+ android:protectionLevel="normal" />
<!-- Allows applications to act as network scorers. @hide @SystemApi-->
<permission android:name="android.permission.SCORE_NETWORKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
@@ -1212,68 +1206,68 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.BLUETOOTH"
- android:description="@string/permdesc_bluetooth"
- android:label="@string/permlab_bluetooth"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_bluetooth"
+ android:label="@string/permlab_bluetooth"
+ android:protectionLevel="normal" />
<!-- Allows applications to discover and pair bluetooth devices.
<p>Protection level: normal
-->
<permission android:name="android.permission.BLUETOOTH_ADMIN"
- android:description="@string/permdesc_bluetoothAdmin"
- android:label="@string/permlab_bluetoothAdmin"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_bluetoothAdmin"
+ android:label="@string/permlab_bluetoothAdmin"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to
allow or disallow phonebook access or message access.
This is not available to third party applications. -->
<permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Control access to email providers exclusively for Bluetooth
@hide
-->
<permission android:name="android.permission.BLUETOOTH_MAP"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows bluetooth stack to access files
@hide This should only be used by Bluetooth apk.
-->
<permission android:name="android.permission.BLUETOOTH_STACK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows applications to perform I/O operations over NFC.
<p>Protection level: normal
-->
<permission android:name="android.permission.NFC"
- android:description="@string/permdesc_nfc"
- android:label="@string/permlab_nfc"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_nfc"
+ android:label="@string/permlab_nfc"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
@hide -->
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows a system application to access hardware packet offload capabilities.
@hide -->
<permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi
@hide -->
<permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows access to the loop radio (Android@Home mesh network) device.
@hide -->
<permission android:name="android.permission.LOOP_RADIO"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows sending and receiving handover transfer status from Wifi and Bluetooth
@hide -->
<permission android:name="android.permission.NFC_HANDOVER_STATUS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ================================== -->
<!-- Permissions for accessing accounts -->
@@ -1292,15 +1286,15 @@
<p>Protection level: dangerous
-->
<permission android:name="android.permission.GET_ACCOUNTS"
- android:permissionGroup="android.permission-group.CONTACTS"
- android:protectionLevel="dangerous"
- android:description="@string/permdesc_getAccounts"
- android:label="@string/permlab_getAccounts" />
+ android:permissionGroup="android.permission-group.CONTACTS"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_getAccounts"
+ android:label="@string/permlab_getAccounts" />
<!-- @SystemApi Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for accessing hardware that may effect battery life-->
@@ -1311,34 +1305,34 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
- android:description="@string/permdesc_changeWifiMulticastState"
- android:label="@string/permlab_changeWifiMulticastState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeWifiMulticastState"
+ android:label="@string/permlab_changeWifiMulticastState"
+ android:protectionLevel="normal" />
<!-- Allows access to the vibrator.
<p>Protection level: normal
-->
<permission android:name="android.permission.VIBRATE"
- android:label="@string/permlab_vibrate"
- android:description="@string/permdesc_vibrate"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_vibrate"
+ android:description="@string/permdesc_vibrate"
+ android:protectionLevel="normal" />
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming.
<p>Protection level: normal
-->
<permission android:name="android.permission.WAKE_LOCK"
- android:label="@string/permlab_wakeLock"
- android:description="@string/permdesc_wakeLock"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_wakeLock"
+ android:description="@string/permdesc_wakeLock"
+ android:protectionLevel="normal" />
<!-- Allows using the device's IR transmitter, if available.
<p>Protection level: normal
-->
<permission android:name="android.permission.TRANSMIT_IR"
- android:label="@string/permlab_transmitIr"
- android:description="@string/permdesc_transmitIr"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_transmitIr"
+ android:description="@string/permdesc_transmitIr"
+ android:protectionLevel="normal" />
<!-- ==================================================== -->
<!-- Permissions related to changing audio settings -->
@@ -1349,9 +1343,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"
- android:label="@string/permlab_modifyAudioSettings"
- android:description="@string/permdesc_modifyAudioSettings"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_modifyAudioSettings"
+ android:description="@string/permdesc_modifyAudioSettings"
+ android:protectionLevel="normal" />
<!-- ================================== -->
<!-- Permissions for accessing hardware -->
@@ -1361,68 +1355,68 @@
<!-- @SystemApi Allows an application to manage preferences and permissions for USB devices
@hide -->
<permission android:name="android.permission.MANAGE_USB"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to access the MTP USB kernel driver.
For use only by the device side MTP implementation.
@hide -->
<permission android:name="android.permission.ACCESS_MTP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows access to hardware peripherals. Intended only for hardware testing.
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.HARDWARE_TEST"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows access to FM
@hide This is not a third-party API (intended for system apps).-->
<permission android:name="android.permission.ACCESS_FM_RADIO"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows access to configure network interfaces, configure/use IPSec, etc.
@hide -->
<permission android:name="android.permission.NET_ADMIN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows registration for remote audio playback. @hide -->
<permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
built-in tuners and HDMI-in's.
@hide This should only be used by OEM's TvInputService's.
-->
<permission android:name="android.permission.TV_INPUT_HARDWARE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows to capture a frame of TV input hardware such as
built-in tuners and HDMI-in's.
@hide <p>Not for use by third-party applications.
-->
<permission android:name="android.permission.CAPTURE_TV_INPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide Allows TvInputService to access DVB device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DVB_DEVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide Allows enabling/disabling OEM unlock
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.OEM_UNLOCK_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows querying state of PersistentDataBlock
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_PDB_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows system update service to notify device owner about pending updates.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- =========================================== -->
<!-- Permissions associated with camera and image capture -->
@@ -1433,12 +1427,12 @@
a camera is in use by an application.
@hide -->
<permission android:name="android.permission.CAMERA_DISABLE_TRANSMIT_LED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows sending the camera service notifications about system-wide events.
@hide -->
<permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- =========================================== -->
<!-- Permissions associated with telephony state -->
@@ -1449,50 +1443,50 @@
Does not include placing calls.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MODIFY_PHONE_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows read only access to precise phone state.
@hide Pending API council approval -->
<permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows read access to privileged phone state.
@hide Used internally. -->
<permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
corresponds to a device SIM.
@hide -->
<permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_CALL_PROVIDER.
@hide -->
<permission android:name="android.permission.REGISTER_CALL_PROVIDER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_CONNECTION_MANAGER
@hide -->
<permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.InCallService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
-->
<permission android:name="android.permission.BIND_INCALL_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.CallScreeningService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
-->
<permission android:name="android.permission.BIND_SCREENING_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
@@ -1501,24 +1495,24 @@
@SystemApi
@hide -->
<permission android:name="android.permission.BIND_CONNECTION_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
-->
<permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to control the in-call experience.
@hide -->
<permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to receive STK related commands.
@hide -->
<permission android:name="android.permission.RECEIVE_STK_COMMANDS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
@@ -1528,7 +1522,7 @@
<!-- @SystemApi Allows an application to write to internal media storage
@hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to manage access to documents, usually as part
of a document picker.
@@ -1538,14 +1532,14 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.MANAGE_DOCUMENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to cache content.
<p>Not for use by third-party applications.
<p>Protection level: signature
-->
<permission android:name="android.permission.CACHE_CONTENT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for screenlock -->
@@ -1556,9 +1550,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.DISABLE_KEYGUARD"
- android:description="@string/permdesc_disableKeyguard"
- android:label="@string/permlab_disableKeyguard"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_disableKeyguard"
+ android:label="@string/permlab_disableKeyguard"
+ android:protectionLevel="normal" />
<!-- ================================== -->
<!-- Permissions to access other installed applications -->
@@ -1567,9 +1561,9 @@
<!-- @deprecated No longer enforced. -->
<permission android:name="android.permission.GET_TASKS"
- android:label="@string/permlab_getTasks"
- android:description="@string/permdesc_getTasks"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_getTasks"
+ android:description="@string/permdesc_getTasks"
+ android:protectionLevel="normal" />
<!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
give access to task information. We need this new one because there are
@@ -1582,99 +1576,99 @@
@hide
@SystemApi -->
<permission android:name="android.permission.REAL_GET_TASKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to start a task from a ActivityManager#RecentTaskInfo.
@hide -->
<permission android:name="android.permission.START_TASKS_FROM_RECENTS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
across the users on the device, using singleton services and
user-targeted broadcasts. This permission is not available to
third party applications. -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
that removes restrictions on where broadcasts can be sent and allows other
types of interactions
@hide -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer" />
<!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
users on the device. This permission is not available to
third party applications. -->
<permission android:name="android.permission.MANAGE_USERS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
- android:protectionLevel="signature"
- android:label="@string/permlab_manageProfileAndDeviceOwners"
- android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+ android:protectionLevel="signature"
+ android:label="@string/permlab_manageProfileAndDeviceOwners"
+ android:description="@string/permdesc_manageProfileAndDeviceOwners" />
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
<permission android:name="android.permission.GET_DETAILED_TASKS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to change the Z-order of tasks.
<p>Protection level: normal
-->
<permission android:name="android.permission.REORDER_TASKS"
- android:label="@string/permlab_reorderTasks"
- android:description="@string/permdesc_reorderTasks"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_reorderTasks"
+ android:description="@string/permdesc_reorderTasks"
+ android:protectionLevel="normal" />
<!-- @hide Allows an application to change to remove/kill tasks -->
<permission android:name="android.permission.REMOVE_TASKS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
<permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to start any activity, regardless of permission
protection or exported state.
@hide -->
<permission android:name="android.permission.START_ANY_ACTIVITY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
API is no longer supported. -->
<permission android:name="android.permission.RESTART_PACKAGES"
- android:label="@string/permlab_killBackgroundProcesses"
- android:description="@string/permdesc_killBackgroundProcesses"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="normal" />
<!-- Allows an application to call
{@link android.app.ActivityManager#killBackgroundProcesses}.
<p>Protection level: normal
-->
<permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
- android:label="@string/permlab_killBackgroundProcesses"
- android:description="@string/permdesc_killBackgroundProcesses"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_killBackgroundProcesses"
+ android:description="@string/permdesc_killBackgroundProcesses"
+ android:protectionLevel="normal" />
<!-- @SystemApi @hide Allows an application to query process states and current
OOM adjustment scores.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi @hide Allows an application to retrieve a package's importance.
This permission is not available to third party applications. -->
<permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows use of PendingIntent.getIntent().
@hide -->
<permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions affecting the display of other applications -->
@@ -1697,9 +1691,9 @@
Settings.canDrawOverlays()}.
<p>Protection level: signature -->
<permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
- android:label="@string/permlab_systemAlertWindow"
- android:description="@string/permdesc_systemAlertWindow"
- android:protectionLevel="signature|preinstalled|appop|pre23|development" />
+ android:label="@string/permlab_systemAlertWindow"
+ android:description="@string/permdesc_systemAlertWindow"
+ android:protectionLevel="signature|preinstalled|appop|pre23|development" />
<!-- ================================== -->
<!-- Permissions affecting the system wallpaper -->
@@ -1710,17 +1704,17 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.SET_WALLPAPER"
- android:label="@string/permlab_setWallpaper"
- android:description="@string/permdesc_setWallpaper"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setWallpaper"
+ android:description="@string/permdesc_setWallpaper"
+ android:protectionLevel="normal" />
<!-- Allows applications to set the wallpaper hints.
<p>Protection level: normal
-->
<permission android:name="android.permission.SET_WALLPAPER_HINTS"
- android:label="@string/permlab_setWallpaperHints"
- android:description="@string/permdesc_setWallpaperHints"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setWallpaperHints"
+ android:description="@string/permdesc_setWallpaperHints"
+ android:protectionLevel="normal" />
<!-- ============================================ -->
<!-- Permissions for changing the system clock -->
@@ -1730,15 +1724,15 @@
<!-- @SystemApi Allows applications to set the system time.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_TIME"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows applications to set the system time zone.
<p>Protection level: normal
-->
<permission android:name="android.permission.SET_TIME_ZONE"
- android:label="@string/permlab_setTimeZone"
- android:description="@string/permdesc_setTimeZone"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_setTimeZone"
+ android:description="@string/permdesc_setTimeZone"
+ android:protectionLevel="normal" />
<!-- ==================================================== -->
<!-- Permissions related to changing status bar -->
@@ -1749,9 +1743,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.EXPAND_STATUS_BAR"
- android:label="@string/permlab_expandStatusBar"
- android:description="@string/permdesc_expandStatusBar"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_expandStatusBar"
+ android:description="@string/permdesc_expandStatusBar"
+ android:protectionLevel="normal" />
<!-- ============================================================== -->
<!-- Permissions related to adding/removing shortcuts from Launcher -->
@@ -1762,17 +1756,17 @@
<p>Protection level: normal
-->
<permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
- android:label="@string/permlab_install_shortcut"
- android:description="@string/permdesc_install_shortcut"
- android:protectionLevel="normal"/>
+ android:label="@string/permlab_install_shortcut"
+ android:description="@string/permdesc_install_shortcut"
+ android:protectionLevel="normal"/>
<!-- Allows an application to uninstall a shortcut in Launcher.
<p>Protection level: normal
-->
<permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
- android:label="@string/permlab_uninstall_shortcut"
- android:description="@string/permdesc_uninstall_shortcut"
- android:protectionLevel="normal"/>
+ android:label="@string/permlab_uninstall_shortcut"
+ android:description="@string/permdesc_uninstall_shortcut"
+ android:protectionLevel="normal"/>
<!-- ==================================================== -->
<!-- Permissions related to accessing sync settings -->
@@ -1783,25 +1777,25 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.READ_SYNC_SETTINGS"
- android:description="@string/permdesc_readSyncSettings"
- android:label="@string/permlab_readSyncSettings"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_readSyncSettings"
+ android:label="@string/permlab_readSyncSettings"
+ android:protectionLevel="normal" />
<!-- Allows applications to write the sync settings.
<p>Protection level: normal
-->
<permission android:name="android.permission.WRITE_SYNC_SETTINGS"
- android:description="@string/permdesc_writeSyncSettings"
- android:label="@string/permlab_writeSyncSettings"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_writeSyncSettings"
+ android:label="@string/permlab_writeSyncSettings"
+ android:protectionLevel="normal" />
<!-- Allows applications to read the sync stats.
<p>Protection level: normal
-->
<permission android:name="android.permission.READ_SYNC_STATS"
- android:description="@string/permdesc_readSyncStats"
- android:label="@string/permlab_readSyncStats"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_readSyncStats"
+ android:label="@string/permlab_readSyncStats"
+ android:protectionLevel="normal" />
<!-- ============================================ -->
<!-- Permissions for low-level system interaction -->
@@ -1810,12 +1804,12 @@
<!-- @SystemApi @hide Change the screen compatibility mode of applications -->
<permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- Allows an application to read or write the system settings.
@@ -1830,51 +1824,51 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.WRITE_SETTINGS"
- android:label="@string/permlab_writeSettings"
- android:description="@string/permdesc_writeSettings"
- android:protectionLevel="signature|preinstalled|appop|pre23" />
+ android:label="@string/permlab_writeSettings"
+ android:description="@string/permdesc_writeSettings"
+ android:protectionLevel="signature|preinstalled|appop|pre23" />
<!-- @SystemApi Allows an application to modify the Google service map.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_GSERVICES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to call
{@link android.app.ActivityManager#forceStopPackage}.
@hide -->
<permission android:name="android.permission.FORCE_STOP_PACKAGES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to retrieve the content of the active window
An active window is the window that has fired an accessibility event. -->
<permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Modify the global animation scaling factor.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_ANIMATION_SCALE"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @deprecated This functionality will be removed in the future; please do
not use. Allow an application to make its activities persistent. -->
<permission android:name="android.permission.PERSISTENT_ACTIVITY"
- android:label="@string/permlab_persistentActivity"
- android:description="@string/permdesc_persistentActivity"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_persistentActivity"
+ android:description="@string/permdesc_persistentActivity"
+ android:protectionLevel="normal" />
<!-- Allows an application to find out the space used by any package.
<p>Protection level: normal
-->
<permission android:name="android.permission.GET_PACKAGE_SIZE"
- android:label="@string/permlab_getPackageSize"
- android:description="@string/permdesc_getPackageSize"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_getPackageSize"
+ android:description="@string/permdesc_getPackageSize"
+ android:protectionLevel="normal" />
<!-- @deprecated No longer useful, see
{@link android.content.pm.PackageManager#addPackageToPreferred}
for details. -->
<permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to receive the
{@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
@@ -1890,9 +1884,9 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
- android:label="@string/permlab_receiveBootCompleted"
- android:description="@string/permdesc_receiveBootCompleted"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_receiveBootCompleted"
+ android:description="@string/permdesc_receiveBootCompleted"
+ android:protectionLevel="normal" />
<!-- Allows an application to broadcast sticky intents. These are
broadcasts whose data is held by the system after being finished,
@@ -1901,90 +1895,90 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.BROADCAST_STICKY"
- android:label="@string/permlab_broadcastSticky"
- android:description="@string/permdesc_broadcastSticky"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_broadcastSticky"
+ android:description="@string/permdesc_broadcastSticky"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows mounting and unmounting file systems for removable storage.
<p>Not for use by third-party applications.-->
<permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows formatting file systems for removable storage.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide -->
<permission android:name="android.permission.STORAGE_INTERNAL"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows access to ASEC non-destructive API calls
@hide -->
<permission android:name="android.permission.ASEC_ACCESS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows creation of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_CREATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows destruction of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_DESTROY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows mount / unmount of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows rename of ASEC volumes
@hide -->
<permission android:name="android.permission.ASEC_RENAME"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows applications to write the apn settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_APN_SETTINGS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows applications to change network connectivity state.
<p>Protection level: normal
-->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
- android:description="@string/permdesc_changeNetworkState"
- android:label="@string/permlab_changeNetworkState"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_changeNetworkState"
+ android:label="@string/permlab_changeNetworkState"
+ android:protectionLevel="normal" />
<!-- Allows an application to clear the caches of all installed
applications on the device.
<p>Protection level: system|signature
-->
<permission android:name="android.permission.CLEAR_APP_CACHE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to use any media decoder when decoding for playback
@hide -->
<permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to install and/or uninstall CA certificates on
behalf of the user.
@hide -->
<permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to do certain operations needed for
interacting with the recovery (system update) system.
@hide -->
<permission android:name="android.permission.RECOVERY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows the system to bind to an application's task services
@hide -->
<permission android:name="android.permission.BIND_JOB_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
<!-- Allows an application to initiate configuration updates
@@ -1993,12 +1987,7 @@
it off to the various individual installer components
@hide -->
<permission android:name="android.permission.UPDATE_CONFIG"
- android:protectionLevel="signature|privileged" />
-
- <!-- Allows the system to reset throttling in shortcut manager.
- @hide -->
- <permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|privileged" />
<!-- ========================================= -->
<!-- Permissions for special development tools -->
@@ -2008,40 +1997,40 @@
<!-- @SystemApi Allows an application to read or write the secure system settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_SECURE_SETTINGS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to retrieve state dump information from system services.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DUMP"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to read the low-level system log files.
<p>Not for use by third-party applications, because
Log entries can contain the user's private information. -->
<permission android:name="android.permission.READ_LOGS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Configure an application for debugging.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_DEBUG_APP"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to set the maximum number of (not needed)
application processes that can be running.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_PROCESS_LIMIT"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to control whether activities are immediately
finished when put in the background.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_ALWAYS_FINISH"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allow an application to request that a signal be sent to all persistent processes.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- ==================================== -->
<!-- Private permissions -->
@@ -2050,34 +2039,34 @@
<!-- @SystemApi Allows access to the list of accounts in the Accounts Service. -->
<permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows but does not guarantee access to user passwords at the conclusion of add account
@hide -->
<permission android:name="android.permission.GET_PASSWORD"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows applications to RW to diagnostic resources.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DIAGNOSTIC"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to open, close, or disable the status bar
and its icons.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.STATUS_BAR"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
@hide -->
<permission android:name="android.permission.STATUS_BAR_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to bind to third party quick settings tiles.
<p>Should only be requested by the System, should be required by
TileService declarations.-->
<permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to force a BACK operation on whatever is the
top activity.
@@ -2085,28 +2074,28 @@
@hide
-->
<permission android:name="android.permission.FORCE_BACK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to update device statistics.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.UPDATE_DEVICE_STATS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows an application to collect battery statistics -->
<permission android:name="android.permission.GET_APP_OPS_STATS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to update application operation statistics. Not for
use by third party apps.
@hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
- android:protectionLevel="signature|privileged|installer" />
+ android:protectionLevel="signature|privileged|installer" />
<!-- @SystemApi Allows an application to update the user app op restrictions.
Not for use by third party apps.
@hide -->
<permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer" />
<!-- @SystemApi Allows an application to open windows that are for use by parts
of the system user interface.
@@ -2114,7 +2103,7 @@
@hide
-->
<permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to manage (create, destroy,
Z-order) application tokens in the window manager.
@@ -2122,17 +2111,17 @@
@hide
-->
<permission android:name="android.permission.MANAGE_APP_TOKENS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows System UI to register listeners for events from Window Manager.
@hide -->
<permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows the application to temporarily freeze the screen for a
full-screen transition. -->
<permission android:name="android.permission.FREEZE_SCREEN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to inject user events (keys, touch, trackball)
into the event stream and deliver them to ANY window. Without this
@@ -2141,24 +2130,24 @@
@hide
-->
<permission android:name="android.permission.INJECT_EVENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to register an input filter which filters the stream
of user events (keys, touch, trackball) before they are dispatched to any window. -->
<permission android:name="android.permission.FILTER_EVENTS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
<permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to collect frame statistics -->
<permission android:name="android.permission.FRAME_STATS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to temporary enable accessibility on the device. -->
<permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to watch and control how activities are
started globally in the system. Only for is in debugging
@@ -2167,13 +2156,13 @@
@hide
-->
<permission android:name="android.permission.SET_ACTIVITY_WATCHER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to call the activity manager shutdown() API
to put the higher-level system there into a shutdown state.
@hide -->
<permission android:name="android.permission.SHUTDOWN"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to tell the activity manager to temporarily
stop application switches, putting it into a special mode that
@@ -2181,7 +2170,7 @@
critical UI such as the home screen.
@hide -->
<permission android:name="android.permission.STOP_APP_SWITCHES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to retrieve private information about
the current top activity, such as any assist context it can provide.
@@ -2189,42 +2178,42 @@
@hide
-->
<permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to retrieve the current state of keys and
switches.
<p>Not for use by third-party applications.
@deprecated The API that used this permission has been removed. -->
<permission android:name="android.permission.READ_INPUT_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_INPUT_METHOD"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.media.midi.MidiDeviceService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_MIDI_DEVICE_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.printservice.PrintService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_PRINT_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
to ensure that only the system can bind to it.
@@ -2233,7 +2222,7 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
@@ -2241,65 +2230,65 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_NFC_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by the PrintSpooler to ensure that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a TextService (e.g. SpellCheckerService)
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_TEXT_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.net.VpnService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_VPN_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
to ensure that only the system can bind to it.
<p>Protection level: system|signature
-->
<permission android:name="android.permission.BIND_WALLPAPER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_VOICE_INTERACTION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by hotword enrollment application,
to ensure that only the system can interact with it.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
to ensure that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_REMOTE_DISPLAY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link android.media.tv.TvInputService}
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_TV_INPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi
Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
@@ -2308,7 +2297,7 @@
<p>Not for use by third-party applications. </p>
@hide -->
<permission android:name="android.permission.BIND_TV_REMOTE_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi
Must be required for a virtual remote controller for TV.
@@ -2316,32 +2305,32 @@
<p>Not for use by third-party applications. </p>
@hide -->
<permission android:name="android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to modify parental controls
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
@hide -->
<permission android:name="android.permission.BIND_ROUTE_PROVIDER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by device administration receiver, to ensure that only the
system can interact with it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_DEVICE_ADMIN"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Required to add or remove another application as a device admin.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows low-level access to setting the orientation (actually
rotation) of the screen.
@@ -2349,33 +2338,33 @@
@hide
-->
<permission android:name="android.permission.SET_ORIENTATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows low-level access to setting the pointer speed.
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.SET_POINTER_SPEED"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows low-level access to setting input device calibration.
<p>Not for use by normal applications.
@hide -->
<permission android:name="android.permission.SET_INPUT_CALIBRATION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows low-level access to setting the keyboard layout.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to query tablet mode state and monitor changes
in it.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.TABLET_MODE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to request installing packages. Apps
targeting APIs greater than 22 must hold this permission in
@@ -2383,290 +2372,290 @@
<p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
- android:label="@string/permlab_requestInstallPackages"
- android:description="@string/permdesc_requestInstallPackages"
- android:protectionLevel="normal" />
+ android:label="@string/permlab_requestInstallPackages"
+ android:description="@string/permdesc_requestInstallPackages"
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an application to install packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_PACKAGES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
-->
<permission android:name="android.permission.CLEAR_APP_USER_DATA"
- android:protectionLevel="signature|installer" />
+ android:protectionLevel="signature|installer" />
<!-- @hide Allows an application to get the URI permissions
granted to another application.
<p>Not for use by third-party applications
-->
<permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide Allows an application to clear the URI permissions
granted to another application.
<p>Not for use by third-party applications
-->
<permission
- android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
- android:protectionLevel="signature" />
+ android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to delete cache files.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DELETE_CACHE_FILES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to delete packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DELETE_PACKAGES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to move location of installed package.
@hide -->
<permission android:name="android.permission.MOVE_PACKAGE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to change whether an application component (other than its own) is
enabled or not.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to grant specific permissions.
@hide -->
<permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier" />
<!-- @SystemApi Allows an app that has this permission and the permissions to install packages
to request certain runtime permissions to be granted at installation.
@hide -->
<permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier" />
<!-- @SystemApi Allows an application to revoke specific permissions.
@hide -->
<permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier" />
<!-- @hide Allows an application to observe permission changes. -->
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to take screen shots and more generally
get access to the frame buffer data.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_FRAME_BUFFER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to use InputFlinger's low level features.
@hide -->
<permission android:name="android.permission.ACCESS_INPUT_FLINGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to configure and connect to Wifi displays
@hide -->
<permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to control low-level features of Wifi displays
such as opening an RTSP socket. This permission should only be used
by the display manager.
@hide -->
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to control the color transforms applied to
displays system-wide.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CONTROL_VPN"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.CONTROL_VPN" />
<!-- @SystemApi Allows an application to capture audio output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to capture audio for hotword detection.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to capture video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to capture secure video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to know what content is playing and control its playback.
<p>Not for use by third-party applications due to privacy of media consumption</p> -->
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Required to be able to disable the device (very dangerous!).
<p>Not for use by third-party applications.
@hide
-->
<permission android:name="android.permission.BRICK"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Required to be able to reboot the device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.REBOOT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
- <!-- @SystemApi Allows low-level access to power management.
- <p>Not for use by third-party applications.
- @hide
- -->
- <permission android:name="android.permission.DEVICE_POWER"
- android:protectionLevel="signature" />
+ <!-- @SystemApi Allows low-level access to power management.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.DEVICE_POWER"
+ android:protectionLevel="signature" />
- <!-- Allows access to the PowerManager.userActivity function.
- <p>Not for use by third-party applications. @hide @SystemApi -->
+ <!-- Allows access to the PowerManager.userActivity function.
+ <p>Not for use by third-party applications. @hide @SystemApi -->
<permission android:name="android.permission.USER_ACTIVITY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
- <!-- @hide Allows low-level access to tun tap driver -->
+ <!-- @hide Allows low-level access to tun tap driver -->
<permission android:name="android.permission.NET_TUNNELING"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Run as a manufacturer test application, running as the root user.
Only available when the device is running in manufacturer test mode.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.FACTORY_TEST"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast a notification that an application
package has been removed.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast an SMS receipt notification.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_SMS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to broadcast a WAP PUSH receipt notification.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.BROADCAST_WAP_PUSH"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to broadcast privileged networking requests.
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Not for use by third-party applications. -->
<permission android:name="android.permission.MASTER_CLEAR"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to call any phone number, including emergency
numbers, without going through the Dialer user interface for the user
to confirm the call being placed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CALL_PRIVILEGED"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to perform CDMA OTA provisioning @hide -->
<permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to perform SIM Activation @hide -->
<permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows enabling/disabling location update notifications from
the radio.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows read/write access to the "properties" table in the checkin
database, to change values that get uploaded.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to collect component usage
statistics
<p>Declaring the permission implies intention to use the API and the user of the
device can grant permission through the Settings application. -->
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
- android:protectionLevel="signature|privileged|development|appop" />
+ android:protectionLevel="signature|privileged|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!-- @hide Allows an application to change the app idle state of an app.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
access the network and acquire wakelocks.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Permission an application must hold in order to use
{@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
This is a normal permission: an app requesting it will always be granted the
permission, without the user needing to approve or see it. -->
<permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
- android:protectionLevel="normal" />
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows an application to collect battery statistics -->
<permission android:name="android.permission.BATTERY_STATS"
- android:protectionLevel="signature|privileged|development" />
+ android:protectionLevel="signature|privileged|development" />
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
<permission android:name="android.permission.BACKUP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows a package to launch the secure full-backup confirmation UI.
ONLY the system process may hold this permission.
@hide -->
<permission android:name="android.permission.CONFIRM_FULL_BACKUP"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Must be required by a {@link android.widget.RemoteViewsService},
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_REMOTEVIEWS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to tell the AppWidget service which application
can access AppWidget's data. The normal user flow is that a user
@@ -2675,25 +2664,25 @@
An application that has this permission should honor that contract.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.BIND_APPWIDGET"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
keyguard widget
@hide -->
<permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Internal permission allowing an application to query/set which
applications can bind AppWidgets.
@hide -->
<permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows applications to change the background data setting.
<p>Not for use by third-party applications.
@hide pending API council -->
<permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi This permission can be used on content providers to allow the global
search system to access their data. Typically it used when the
@@ -2704,7 +2693,7 @@
it is used by applications to protect themselves from everyone else
besides global search. -->
<permission android:name="android.permission.GLOBAL_SEARCH"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Internal permission protecting access to the global search
system: ensures that only the system can access the provider
@@ -2714,33 +2703,33 @@
ranking).
@hide -->
<permission android:name="android.permission.GLOBAL_SEARCH_CONTROL"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Internal permission to allows an application to read indexable data.
@hide -->
<permission android:name="android.permission.READ_SEARCH_INDEXABLES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows applications to set a live wallpaper.
@hide XXX Change to signature once the picker is moved to its
own apk as Ghod Intended. -->
<permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows applications to read dream settings and dream state.
@hide -->
<permission android:name="android.permission.READ_DREAM_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows applications to write dream settings, and start or stop dreaming.
@hide -->
<permission android:name="android.permission.WRITE_DREAM_STATE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allow an application to read and write the cache partition.
@hide -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by default container service so that only
the system can bind to it and use it to copy
@@ -2748,67 +2737,67 @@
accessible to the system.
@hide -->
<permission android:name="android.permission.COPY_PROTECTED_DATA"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Internal permission protecting access to the encryption methods
@hide
-->
<permission android:name="android.permission.CRYPT_KEEPER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to read historical network usage for
specific networks and applications. @hide -->
<permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to manage network policies (such as warning and disable
limits) and to define application-specific rules. @hide -->
<permission android:name="android.permission.MANAGE_NETWORK_POLICY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
by system services like download manager and media server. Not for use by
third party apps. @hide -->
<permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- C2DM permission.
@hide Used internally.
-->
<permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
<!-- @SystemApi @hide Package verifier needs to have this permission before the PackageManager will
trust it to verify packages.
-->
<permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by package verifier receiver, to ensure that only the
system can interact with it.
@hide
-->
<permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
PackageManager will trust it to verify intent filters.
-->
<permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Must be required by intent filter verifier receiver, to ensure that only the
system can interact with it.
@hide
-->
<permission android:name="android.permission.BIND_INTENT_FILTER_VERIFIER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows applications to access serial ports via the SerialManager.
@hide -->
<permission android:name="android.permission.SERIAL_PORT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows the holder to access content providers from outside an ApplicationThread.
This permission is enforced by the ActivityManagerService on the corresponding APIs,
@@ -2817,27 +2806,27 @@
@hide
-->
<permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to hold an UpdateLock, recommending that a headless
OTA reboot *not* occur while the lock is held.
@hide -->
<permission android:name="android.permission.UPDATE_LOCK"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to read the current set of notifications, including
any metadata and intents attached.
@hide -->
<permission android:name="android.permission.ACCESS_NOTIFICATIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Marker permission for applications that wish to access notification policy.
<p>Protection level: normal
-->
<permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
- android:description="@string/permdesc_access_notification_policy"
- android:label="@string/permlab_access_notification_policy"
- android:protectionLevel="normal" />
+ android:description="@string/permdesc_access_notification_policy"
+ android:label="@string/permlab_access_notification_policy"
+ android:protectionLevel="normal" />
<!-- Allows modification of do not disturb rules and policies. Only allowed for system
processes.
@@ -2848,42 +2837,42 @@
<!-- Allows access to keyguard secure storage. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to control keyguard. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.CONTROL_KEYGUARD"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to listen to trust changes. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.TRUST_LISTENER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to provide a trust agent.
@hide For security reasons, this is a platform-only permission. -->
<permission android:name="android.permission.PROVIDE_TRUST_AGENT"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to launch the trust agent settings activity.
@hide -->
<permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Must be required by an {@link
android.service.trust.TrustAgentService},
to ensure that only the system can bind to it.
@hide -->
<permission android:name="android.permission.BIND_TRUST_AGENT"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link
android.service.notification.NotificationListenerService},
@@ -2891,7 +2880,7 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link
android.service.notification.NotificationRankerService to ensure that only the system can bind to it.
@@ -2899,7 +2888,7 @@
@hide This is not a third-party API (intended for system apps). -->
-->
<permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link
android.service.chooser.ChooserTargetService}, to ensure that
@@ -2907,7 +2896,7 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by a {@link
android.service.notification.ConditionProviderService},
@@ -2915,57 +2904,57 @@
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Must be required by an {@link android.service.dreams.DreamService},
to ensure that only the system can bind to it.
<p>Protection level: signature
-->
<permission android:name="android.permission.BIND_DREAM_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
carrier setup application to enforce that this permission is required
@hide This is not a third-party API (intended for OEMs and system apps). -->
<permission android:name="android.permission.INVOKE_CARRIER_SETUP"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to listen for network condition observations.
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to provision and access DRM certificates
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Api Allows an application to manage media projection sessions.
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to read install sessions
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.READ_INSTALL_SESSIONS"
- android:label="@string/permlab_readInstallSessions"
- android:description="@string/permdesc_readInstallSessions"
- android:protectionLevel="normal"/>
+ android:label="@string/permlab_readInstallSessions"
+ android:description="@string/permdesc_readInstallSessions"
+ android:protectionLevel="normal"/>
<!-- @SystemApi Allows an application to remove DRM certificates
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.REMOVE_DRM_CERTIFICATES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @deprecated Use {@link android.Manifest.permission#BIND_CARRIER_SERVICES} instead -->
<permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to interact with the currently active
{@link android.service.voice.VoiceInteractionService}.
@hide -->
<permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- The system process that is allowed to bind to services in carrier apps will
have this permission. Carrier apps should use this permission to protect
@@ -2973,9 +2962,9 @@
<p>Protection level: system|signature
-->
<permission android:name="android.permission.BIND_CARRIER_SERVICES"
- android:label="@string/permlab_bindCarrierServices"
- android:description="@string/permdesc_bindCarrierServices"
- android:protectionLevel="signature|privileged" />
+ android:label="@string/permlab_bindCarrierServices"
+ android:description="@string/permdesc_bindCarrierServices"
+ android:protectionLevel="signature|privileged" />
<!-- Allows an application to query whether DO_NOT_ASK_CREDENTIALS_ON_BOOT
flag is set.
@@ -3021,7 +3010,7 @@
<!-- Allows the holder to access the ephemeral applications on the device.
@hide -->
<permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows receiving the usage of media resource e.g. video/audio codec and
graphic memory.
@@ -3033,7 +3022,7 @@
APIs given by {@link SoundTriggerManager}.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows trusted applications to dispatch managed provisioning message to Managed
Provisioning app. If requesting app does not have permission, it will be ignored.
@@ -3057,17 +3046,17 @@
the system can bind to it.
<p>Protection level: signature -->
<permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Required to make calls to {@link android.service.vr.IVrManager}.
@hide -->
<permission android:name="android.permission.ACCESS_VR_MANAGER"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature" />
<!-- Allows an application to whitelist tasks during lock task mode
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
- android:protectionLevel="signature|setup" />
+ android:protectionLevel="signature|setup" />
<!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
in the N-release and later.
@@ -3088,13 +3077,12 @@
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
<activity android:name="com.android.internal.app.ChooserActivity"
- android:theme="@style/Theme.DeviceDefault.Resolver"
- android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true"
- android:documentLaunchMode="never"
- android:relinquishTaskIdentity="true"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
- android:process=":ui">
+ android:theme="@style/Theme.DeviceDefault.Resolver"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:process=":ui">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3102,102 +3090,102 @@
</intent-filter>
</activity>
<activity android:name="com.android.internal.app.IntentForwarderActivity"
- android:finishOnCloseSystemDialogs="true"
- android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:label="@string/user_owner_label"
- android:exported="true"
- >
+ android:finishOnCloseSystemDialogs="true"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:label="@string/user_owner_label"
+ android:exported="true"
+ >
</activity>
<activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
- android:targetActivity="com.android.internal.app.IntentForwarderActivity"
- android:exported="true"
- android:label="@string/user_owner_label">
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:exported="true"
+ android:label="@string/user_owner_label">
</activity-alias>
<activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
- android:targetActivity="com.android.internal.app.IntentForwarderActivity"
- android:icon="@drawable/ic_corp_icon"
- android:exported="true"
- android:label="@string/managed_profile_label">
+ android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+ android:icon="@drawable/ic_corp_icon"
+ android:exported="true"
+ android:label="@string/managed_profile_label">
</activity-alias>
<activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/heavy_weight_switcher_title"
- android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/heavy_weight_switcher_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
- android:configChanges="orientation|keyboardHidden"
- android:process=":ui">
+ android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.DisableCarModeActivity"
- android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.DumpHeapActivity"
- android:theme="@style/Theme.Translucent.NoTitleBar"
- android:label="@string/dump_heap_title"
- android:finishOnCloseSystemDialogs="true"
- android:noHistory="true"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Translucent.NoTitleBar"
+ android:label="@string/dump_heap_title"
+ android:finishOnCloseSystemDialogs="true"
+ android:noHistory="true"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<provider android:name="com.android.server.am.DumpHeapProvider"
- android:authorities="com.android.server.heapdump"
- android:grantUriPermissions="true"
- android:multiprocess="false"
- android:singleUser="true" />
+ android:authorities="com.android.server.heapdump"
+ android:grantUriPermissions="true"
+ android:multiprocess="false"
+ android:singleUser="true" />
<activity android:name="android.accounts.ChooseAccountActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/choose_account_label"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/choose_account_label"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.ChooseAccountTypeActivity"
- android:excludeFromRecents="true"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/choose_account_label"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/choose_account_label"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.CantAddAccountActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
+ android:process=":ui">
</activity>
<activity android:name="android.accounts.GrantCredentialsPermissionActivity"
- android:excludeFromRecents="true"
- android:exported="true"
- android:theme="@style/Theme.Material.Light.DialogWhenLarge"
- android:process=":ui">
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:theme="@style/Theme.Material.Light.DialogWhenLarge"
+ android:process=":ui">
</activity>
<activity android:name="android.content.SyncActivityTooManyDeletes"
- android:theme="@style/Theme.Material.Light.Dialog"
- android:label="@string/sync_too_many_deletes"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog"
+ android:label="@string/sync_too_many_deletes"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.ShutdownActivity"
- android:permission="android.permission.SHUTDOWN"
- android:theme="@style/Theme.NoDisplay"
- android:excludeFromRecents="true">
+ android:permission="android.permission.SHUTDOWN"
+ android:theme="@style/Theme.NoDisplay"
+ android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_REQUEST_SHUTDOWN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3209,9 +3197,9 @@
</activity>
<activity android:name="com.android.internal.app.NetInitiatedActivity"
- android:theme="@style/Theme.Material.Light.Dialog.Alert"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.SystemUserHomeActivity"
@@ -3228,9 +3216,9 @@
<!-- Activity to prompt user if it's ok to create a new user sandbox for a
specified account. -->
<activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
- android:excludeFromRecents="true"
- android:process=":ui"
- android:theme="@style/Theme.Material.Light.Dialog.Alert">
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert">
<intent-filter android:priority="1000">
<action android:name="android.os.action.CREATE_USER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3238,20 +3226,20 @@
</activity>
<activity android:name="com.android.internal.app.UnlaunchableAppActivity"
- android:theme="@style/Theme.Material.Light.Dialog.Alert"
- android:excludeFromRecents="true"
- android:process=":ui">
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
+ android:excludeFromRecents="true"
+ android:process=":ui">
</activity>
<receiver android:name="com.android.server.BootReceiver"
- android:systemUserOnly="true">
+ android:systemUserOnly="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="com.android.server.updates.CertPinInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_PINS" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3259,7 +3247,7 @@
</receiver>
<receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3267,7 +3255,7 @@
</receiver>
<receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3275,7 +3263,7 @@
</receiver>
<receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_APN_DB" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3283,7 +3271,7 @@
</receiver>
<receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -3291,23 +3279,15 @@
</receiver>
<receiver android:name="com.android.server.updates.TzDataInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
+ android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
<action android:name="android.intent.action.UPDATE_TZDATA" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
- <receiver android:name="com.android.server.updates.SELinuxPolicyInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
- <intent-filter>
- <action android:name="android.intent.action.UPDATE_SEPOLICY" />
- <data android:scheme="content" android:host="*" android:mimeType="*/*" />
- </intent-filter>
- </receiver>
-
<receiver android:name="com.android.server.MasterClearReceiver"
- android:permission="android.permission.MASTER_CLEAR">
+ android:permission="android.permission.MASTER_CLEAR">
<intent-filter
android:priority="100" >
<!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
@@ -3320,12 +3300,12 @@
</receiver>
<service android:name="android.hardware.location.GeofenceHardwareService"
- android:permission="android.permission.LOCATION_HARDWARE"
- android:exported="false" />
+ android:permission="android.permission.LOCATION_HARDWARE"
+ android:exported="false" />
<service android:name="com.android.internal.backup.LocalTransportService"
- android:permission="android.permission.CONFIRM_FULL_BACKUP"
- android:exported="false">
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:exported="false">
<intent-filter>
<action android:name="android.backup.TRANSPORT_HOST" />
</intent-filter>
@@ -3350,9 +3330,9 @@
</service>
<service
- android:name="com.android.server.pm.BackgroundDexOptService"
- android:exported="true"
- android:permission="android.permission.BIND_JOB_SERVICE">
+ android:name="com.android.server.pm.BackgroundDexOptService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE">
</service>
</application>
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index f440389..0bee8b9 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -106,7 +106,7 @@
// OEMs cannot define permissions in the platform namespace
for (String permission : declaredPermissionsMap.keySet()) {
- assertFalse("Cannot define permission " + permission + " in android namespace",
+ assertFalse("Cannot define permission in android namespace",
permission.startsWith(PLATFORM_ROOT_NAMESPACE));
}
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
index bceaacc..d0c1a81 100644
--- a/tests/tests/print/Android.mk
+++ b/tests/tests/print/Android.mk
@@ -27,7 +27,7 @@
LOCAL_PACKAGE_NAME := CtsPrintTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil android-support-test
LOCAL_SDK_VERSION := test_current
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
index f8f610a..0c6f411 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_ContactsTest.java
@@ -29,6 +29,7 @@
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
import android.provider.cts.ContactsContract_TestDataBuilder.TestRawContact;
import android.provider.cts.contacts.ContactUtil;
@@ -228,6 +229,15 @@
new long[]{contact.getId()}
);
+ // Contacts.CONTENT_FILTER_URI
+ DatabaseAsserts.checkProjection(mResolver,
+ Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon().appendEncodedPath("xxx")
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).build(),
+ PROJECTION,
+ new long[]{contact.getId()}
+ );
+
// Contacts.CONTENT_LOOKUP_URI
DatabaseAsserts.checkProjection(mResolver,
Contacts.getLookupUri(contactId, lookupKey),
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java
index 33d3a28..62c6fdd 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_DataTest.java
@@ -36,6 +36,7 @@
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Contacts.Entity;
import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.RawContactsEntity;
import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
@@ -533,6 +534,37 @@
assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[6]);
}
+ public void testEnterpriseCallableFilterByNameOrOrganization_returnsCorrectDataRows()
+ throws Exception {
+ long[] ids = setupContactablesTestData();
+ Uri uri = Uri.withAppendedPath(Callable.ENTERPRISE_CONTENT_FILTER_URI, "doe").buildUpon()
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT))
+ .build();
+ // Only callables belonging to John Doe (name) and Cold Tamago (organization) are returned.
+ assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[5],
+ sContentValues[6]);
+ }
+
+ public void testEnterpriseCallableFilterByNumber_returnsCorrectDataRows() throws Exception {
+ long[] ids = setupContactablesTestData();
+ Uri uri = Uri.withAppendedPath(Callable.ENTERPRISE_CONTENT_FILTER_URI, "510").buildUpon()
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT))
+ .build();
+ assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[1]);
+ }
+
+ public void testEnterpriseCallableFilterBySipAddress_returnsCorrectDataRows()
+ throws Exception {
+ long[] ids = setupContactablesTestData();
+ Uri uri = Uri.withAppendedPath(Callable.ENTERPRISE_CONTENT_FILTER_URI, "mysip").buildUpon()
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT))
+ .build();
+ assertCursorStoredValuesWithRawContactsFilter(uri, ids, sContentValues[6]);
+ }
+
public void testDataInsert_updatesContactLastUpdatedTimestamp() {
DatabaseAsserts.ContactIdPair ids = DatabaseAsserts.assertAndCreateContact(mResolver);
long baseTime = ContactUtil.queryContactLastUpdatedTimestamp(mResolver, ids.mContactId);
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java
index 847e357..b049996 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_SearchSnippetsTest.java
@@ -28,6 +28,7 @@
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.SearchSnippets;
import android.provider.cts.ContactsContract_TestDataBuilder.TestContact;
@@ -85,6 +86,15 @@
assertCursorStoredValuesWithContactsFilter(uri, ids);
}
+ public void testEnterpriseSearchSnippets_NoMatch() throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).appendPath("nomatch").build();
+
+ assertCursorStoredValuesWithContactsFilter(uri, ids);
+ }
+
public void testSearchSnippets_MatchEmailAddressCorrectSnippet() throws Exception {
long[] ids = setupTestData();
final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -96,6 +106,18 @@
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
}
+ public void testEnterpriseSearchSnippets_MatchEmailAddressCorrectSnippet() throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendPath("farm").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[1]);
+ expected.put(SearchSnippets.SNIPPET, "eggs@[farmers].org");
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
public void testSearchSnippets_MatchPhoneNumberCorrectSnippet() throws Exception {
long[] ids = setupTestData();
final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -107,6 +129,18 @@
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
}
+ public void testEnterpriseSearchSnippets_MatchPhoneNumberCorrectSnippet() throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendPath("510").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[0]);
+ expected.put(SearchSnippets.SNIPPET, "[510-123-5769]");
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
public void testSearchSnippets_MatchPostalAddressCorrectSnippet() throws Exception {
long[] ids = setupTestData();
final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -118,6 +152,18 @@
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
}
+ public void testEnterpriseSearchSnippets_MatchPostalAddressCorrectSnippet() throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendPath("street").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[2]);
+ expected.put(SearchSnippets.SNIPPET, "123 Main [Street] Unit 3113\u2026");
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
public void testSearchSnippets_LongMatchTruncation() throws Exception {
long[] ids = setupTestData();
final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -129,6 +175,18 @@
assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
}
+ public void testEnterpriseSearchSnippets_LongMatchTruncation() throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendPath("over").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[2]);
+ expected.put(SearchSnippets.SNIPPET, "\u2026dog jumps [over] the quick\u2026");
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
public void testSearchSnippets_MultipleMatchesCorrectSnippet() throws Exception {
long[] ids = setupTestData();
final Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon()
@@ -145,6 +203,23 @@
assertCursorStoredValuesWithContactsFilter(uri, ids, expected, expected2);
}
+ public void testEnterpriseSearchSnippets_MultipleMatchesCorrectSnippet() throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendPath("123").appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT)).build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[1]);
+ expected.put(SearchSnippets.SNIPPET, "[123-456-7890]");
+
+ final ContentValues expected2 = new ContentValues();
+ expected2.put(Contacts._ID, ids[2]);
+ expected2.put(SearchSnippets.SNIPPET, "[123] Main Street Unit 3113\u2026");
+
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected, expected2);
+ }
+
/**
* Tests that if deferred snippeting is indicated, the provider will not perform formatting
* of the snippet for a single word query.
@@ -163,6 +238,25 @@
}
/**
+ * Tests that if deferred snippeting is indicated, the provider will not perform formatting
+ * of the snippet for a single word query.
+ */
+ public void testEnterpriseSearchSnippets_DeferredSnippetingSingleWordQuerySnippetDeferred()
+ throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1")
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT))
+ .appendPath("510").build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[0]);
+ expected.put(SearchSnippets.SNIPPET, "510-123-5769");
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
+ /**
* Tests that even if deferred snippeting is indicated, a multi-word query will have formatting
* of the snippet done by the provider using SQLite
*/
@@ -180,6 +274,25 @@
}
/**
+ * Tests that even if deferred snippeting is indicated, a multi-word query will have formatting
+ * of the snippet done by the provider using SQLite
+ */
+ public void testEnterpriseSearchSnippets_DeferredSnippetingMultiWordQuerySnippetNotDeferred()
+ throws Exception {
+ long[] ids = setupTestData();
+ final Uri uri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
+ .appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1")
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(Directory.DEFAULT))
+ .appendPath("jumps over").build();
+
+ final ContentValues expected = new ContentValues();
+ expected.put(Contacts._ID, ids[2]);
+ expected.put(SearchSnippets.SNIPPET, "\u2026lazy dog [jumps] [over] the\u2026");
+ assertCursorStoredValuesWithContactsFilter(uri, ids, expected);
+ }
+
+ /**
* Given a uri, performs a query on the contacts provider for that uri and asserts that the
* cursor returned from the query matches the expected results.
*
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
index d731561..173c3ea 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
@@ -428,8 +428,32 @@
/////////////////////////////////////////////////////////////////////////
// Test out-of-range result.
+
+// When a result is ulong, it can take on values not representable on
+// the Java side, where there are no unsigned integral types and long
+// is the largest integral type -- i.e., all values in the range
+// (MAX_LONG, MAX_ULONG] are not representable in Java. The reflected
+// result_*.get() methods throw an exception if the result value is
+// out of range. The globals and reduction kernels below allow a test
+// case on the Java side to describe what kind of result we should
+// produce -- in particular, what to use for an in-range value and an
+// out-of-range value, and where (if anywhere) to put an out-of-range
+// value within the result (which might be scalar, vector, array of
+// scalar, or array of vector).
+
// We don't care about the input at all.
// We use these globals to configure the generation of the result.
+// A kernel puts 2*oorrBadResultHalf in the position (if any) of the result
+// given by oorrBadResult, and oorrGoodResult everywhere else.
+// The oorrBadPos encoding is as follows:
+// - For scalar result, 0 = scalar; anything else = nowhere
+// - For vector result, 0..length(vector)-1 = corresponding vector component
+// (0 = x, 1 = y, 2 = z, 3 = w); anything else = nowhere
+// - For array of scalar result, 0..length(array)-1 = corresponding array element;
+// anything else = nowhere
+// - For array of vector result, 0..length(vector)*length(array)-1 = corresponding
+// vector component C of corresponding array element E; anything else = nowhere
+// (encoding is C + length(vector)*E)
ulong oorrGoodResult; // the value of a good result
ulong oorrBadResultHalf; // half the value of a bad result
// ("half" because Java can only set the global from long not from ulong)
diff --git a/tests/tests/speech/Android.mk b/tests/tests/speech/Android.mk
index 3d95053..68e0cba 100755
--- a/tests/tests/speech/Android.mk
+++ b/tests/tests/speech/Android.mk
@@ -21,7 +21,7 @@
# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/systemui/Android.mk b/tests/tests/systemui/Android.mk
index 536d2a8..c31d825 100644
--- a/tests/tests/systemui/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -26,7 +26,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/telecom/Android.mk b/tests/tests/telecom/Android.mk
index 5a8922e..27947af 100644
--- a/tests/tests/telecom/Android.mk
+++ b/tests/tests/telecom/Android.mk
@@ -24,7 +24,7 @@
# When built, explicitly put it in the data partition.
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java b/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
index 0f09314..b15a4e8 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SimRestrictedApisTest.java
@@ -265,4 +265,20 @@
} catch (SecurityException expected) {
}
}
+
+ /**
+ * Tests the TelephonyManager.getIccAuthentication() API. This makes a call to
+ * getIccAuthentication() API and expects a SecurityException since the test apk is not
+ * signed by certificate on the SIM.
+ */
+ public void testGetIccAuthentication() {
+ try {
+ if (isSimCardPresent()) {
+ TelephonyManager.getDefault().getIccAuthentication(TelephonyManager.APPTYPE_USIM,
+ TelephonyManager.AUTHTYPE_EAP_AKA, "");
+ fail("Expected SecurityException. App doesn't have carrier privileges.");
+ }
+ } catch (SecurityException expected) {
+ }
+ }
}
diff --git a/tests/tests/text/Android.mk b/tests/tests/text/Android.mk
index 65a93fb..731fa9b 100644
--- a/tests/tests/text/Android.mk
+++ b/tests/tests/text/Android.mk
@@ -23,7 +23,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctsdeviceutillegacy ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctsdeviceutillegacy ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
index 1705326..212d4eb 100644
--- a/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BackspaceTest.java
@@ -59,6 +59,31 @@
}
@SmallTest
+ public void testCRLF() {
+ EditorState state = new EditorState();
+
+ // U+000A is LINE FEED.
+ state.setByString("U+000A |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ // U+000D is CARRIAGE RETURN.
+ state.setByString("U+000D |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+000D U+000A |");
+ backspace(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("U+000A U+000D |");
+ backspace(state, 0);
+ state.assertEquals("U+000A |");
+ backspace(state, 0);
+ state.assertEquals("|");
+ }
+
+ @SmallTest
public void testSurrogatePairs() {
EditorState state = new EditorState();
diff --git a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
index 40ed593..3b226fb 100644
--- a/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ForwardDeleteTest.java
@@ -59,6 +59,30 @@
}
@SmallTest
+ public void testCRLF() {
+ EditorState state = new EditorState();
+
+ // U+000A is LINE FEED.
+ state.setByString("| U+000A");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ // U+000D is CARRIAGE RETURN.
+ state.setByString("| U+000D");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+000D U+000A");
+ forwardDelete(state, 0);
+ state.assertEquals("|");
+
+ state.setByString("| U+000A U+000D");
+ forwardDelete(state, 0);
+ state.assertEquals("| U+000D");
+ forwardDelete(state, 0);
+ }
+
+ @SmallTest
public void testSurrogatePairs() {
EditorState state = new EditorState();
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index a159da9..431c754 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -592,13 +592,6 @@
}
@SmallTest
- public void testAddLinks_partiallyMatchesUrlWithInvalidRequestParameter() throws Exception {
- String url = "http://android.com?p=value";
- assertAddLinksWithWebUrlPartiallyMatches("Should partially match URL with invalid " +
- "request parameter", "http://android.com", url);
- }
-
- @SmallTest
public void testAddLinks_matchesValidUrlWithEmoji() throws Exception {
String url = "Thank\u263A.com";
assertAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
@@ -669,6 +662,48 @@
}
}
+ @SmallTest
+ public void testAddLinks_matchesDomainNameWithDash() throws Exception {
+ String url = "http://a-nd.r-oid.com";
+ assertAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+
+ url = "a-nd.r-oid.com";
+ assertAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+ }
+
+ @SmallTest
+ public void testAddLinks_matchesDomainNameWithUnderscore() throws Exception {
+ String url = "http://a_nd.r_oid.com";
+ assertAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+
+ url = "a_nd.r_oid.com";
+ assertAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+ }
+
+ @SmallTest
+ public void testAddLinks_matchesPathAndQueryWithDollarSign() throws Exception {
+ String url = "http://android.com/path$?v=$val";
+ assertAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+
+ url = "android.com/path$?v=$val";
+ assertAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+ }
+
+ @SmallTest
+ public void testAddLinks_matchesEmptyPathWithQueryParams() throws Exception {
+ String url = "http://android.com?q=v";
+ assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+ url = "android.com?q=v";
+ assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+ url = "http://android.com/?q=v";
+ assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+ url = "android.com/?q=v";
+ assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+ }
+
// EMAIL_ADDRESSES Related Tests
public void testAddLinks_email_matchesShortValidEmail() throws Exception {
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
index af8b4eb..6dd90e3 100644
--- a/tests/tests/transition/Android.mk
+++ b/tests/tests/transition/Android.mk
@@ -24,7 +24,7 @@
# When built, explicitly put it in the data partition.
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index fd01e10..a2e54d0 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -26,7 +26,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
diff --git a/tests/tests/uirendering/res/drawable-nodpi/golden_dashed_oval.png b/tests/tests/uirendering/res/drawable-nodpi/golden_dashed_oval.png
new file mode 100644
index 0000000..c95568a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/golden_dashed_oval.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable/dashed_oval.xml b/tests/tests/uirendering/res/drawable/dashed_oval.xml
new file mode 100644
index 0000000..904b016
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable/dashed_oval.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+ -->
+<shape
+ android:shape="oval"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <stroke
+ android:width="2px"
+ android:dashGap="6px"
+ android:dashWidth="2px"
+ android:color="@android:color/black"
+ />
+</shape>
diff --git a/tests/tests/uirendering/res/layout/frame_layout.xml b/tests/tests/uirendering/res/layout/frame_layout.xml
new file mode 100644
index 0000000..4ceac5d
--- /dev/null
+++ b/tests/tests/uirendering/res/layout/frame_layout.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/frame_layout"
+ android:layout_width="@dimen/test_width"
+ android:layout_height="@dimen/test_height"/>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
index 1e7a832..8360948 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -16,12 +16,18 @@
package android.uirendering.cts.testclasses;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.util.DisplayMetrics;
+
import org.junit.Test;
import static org.junit.Assert.assertFalse;
@@ -114,4 +120,68 @@
})
.runWithoutVerification();
}
+
+ private void testFailureOnBitmapDraw(Bitmap bitmap) {
+ createTest()
+ .addCanvasClient((canvas, width, height) -> {
+ boolean sawException = false;
+ try {
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ } catch (RuntimeException e) {
+ sawException = true;
+ }
+ assertTrue(sawException);
+ })
+ .runWithoutVerification();
+ }
+
+ @Test
+ public void testFailureOnDrawRecycledBitmap() {
+ Bitmap recycledBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ recycledBitmap.recycle();
+ testFailureOnBitmapDraw(recycledBitmap);
+ }
+
+ @Test
+ public void testFailureOnNonPremultipliedBitmap() {
+ Bitmap nonPremultipliedBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+ nonPremultipliedBitmap.setPremultiplied(false);
+ nonPremultipliedBitmap.setHasAlpha(true);
+ testFailureOnBitmapDraw(nonPremultipliedBitmap);
+ }
+
+ @Test
+ public void testDrawScreenWideBitmap() {
+ createTest()
+ .addCanvasClient((canvas, width, height) -> {
+ DisplayMetrics displayMetrics =
+ getActivity().getResources().getDisplayMetrics();
+ assertTrue(displayMetrics.widthPixels <= canvas.getMaximumBitmapWidth());
+ assertTrue(displayMetrics.heightPixels <= canvas.getMaximumBitmapHeight());
+ Bitmap bitmap = Bitmap.createBitmap(displayMetrics.widthPixels,
+ displayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
+ bitmap.eraseColor(Color.RED);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ })
+ .runWithVerifier(new ColorVerifier(Color.RED, 0));
+ }
+
+ @Test
+ public void testDrawLargeBitmap() {
+ // verify that HW and SW pipelines can both draw screen-and-a-half sized bitmap
+ createTest()
+ .addCanvasClient((canvas, width, height) -> {
+ DisplayMetrics displayMetrics =
+ getActivity().getResources().getDisplayMetrics();
+
+ int bWidth = displayMetrics.widthPixels * 3 / 2;
+ int bHeight = displayMetrics.heightPixels * 3 / 2;
+ bWidth = Math.min(bWidth, canvas.getMaximumBitmapWidth());
+ bHeight = Math.min(bHeight, canvas.getMaximumBitmapHeight());
+ Bitmap bitmap = Bitmap.createBitmap(bWidth, bHeight, Bitmap.Config.ARGB_8888);
+ bitmap.eraseColor(Color.RED);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ })
+ .runWithVerifier(new ColorVerifier(Color.RED, 0));
+ }
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
new file mode 100644
index 0000000..3670797
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
@@ -0,0 +1,22 @@
+package android.uirendering.cts.testclasses;
+
+import android.graphics.*;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import org.junit.Test;
+
+@MediumTest
+public class ShapeTests extends ActivityTestBase {
+ @Test
+ public void testDashedOval() {
+ Bitmap goldenBitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+ R.drawable.golden_dashed_oval);
+ createTest()
+ .addLayout(R.layout.frame_layout,
+ view -> view.setBackgroundResource(R.drawable.dashed_oval))
+ .runWithVerifier(new GoldenImageVerifier(goldenBitmap, new MSSIMComparer(0.99)));
+ }
+}
diff --git a/tests/tests/view/Android.mk b/tests/tests/view/Android.mk
index 57dc0ce..ea9ce5a 100644
--- a/tests/tests/view/Android.mk
+++ b/tests/tests/view/Android.mk
@@ -29,7 +29,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := \
- ctsdeviceutil ctstestrunner mockito-target platform-test-annotations
+ ctsdeviceutil ctstestrunner mockito-target platform-test-annotations android-support-test
LOCAL_JNI_SHARED_LIBRARIES := libctsview_jni libnativehelper_compat_libc++
diff --git a/tests/tests/view/jni/Android.mk b/tests/tests/view/jni/Android.mk
index ac7b844..288e250 100644
--- a/tests/tests/view/jni/Android.mk
+++ b/tests/tests/view/jni/Android.mk
@@ -18,6 +18,8 @@
LOCAL_MODULE := libctsview_jni
+LOCAL_CFLAGS += -Werror
+
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
diff --git a/tests/tests/view/jni/CtsViewJniOnLoad.cpp b/tests/tests/view/jni/CtsViewJniOnLoad.cpp
index 2c1e643..1a7ef3c 100644
--- a/tests/tests/view/jni/CtsViewJniOnLoad.cpp
+++ b/tests/tests/view/jni/CtsViewJniOnLoad.cpp
@@ -16,8 +16,8 @@
*/
#include <jni.h>
-#include <utils/Log.h>
#define LOG_TAG "CtsViewJniOnLoad"
+#include <utils/Log.h>
extern int register_android_view_cts_ChoreographerNativeTest(JNIEnv* env);
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index 64ebe39..df1fae9 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -111,15 +111,15 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="70px"
- android:pointerIcon="crosshair">
+ android:pointerShape="crosshair">
<View android:layout_width="match_parent"
android:layout_height="20px"
- android:pointerIcon="help"/>
+ android:pointerShape="help"/>
<View android:layout_width="match_parent"
android:layout_height="20px"/>
<View android:layout_width="match_parent"
android:layout_height="20px"
- android:pointerIcon="@drawable/custom_pointer_icon"/>
+ android:pointerShape="@drawable/custom_pointer_icon"/>
</LinearLayout>
</LinearLayout>
diff --git a/tests/tests/view/src/android/view/cts/MockView.java b/tests/tests/view/src/android/view/cts/MockView.java
index c5e4ab4..f07e991 100644
--- a/tests/tests/view/src/android/view/cts/MockView.java
+++ b/tests/tests/view/src/android/view/cts/MockView.java
@@ -69,7 +69,7 @@
private boolean mCalledComputeScroll = false;
private boolean mCalledDispatchKeyEventPreIme = false;
private boolean mCalledOnKeyPreIme = false;
- private boolean mCalledOnResolvePointerIcon = false;
+ private boolean mCalledGetPointerIcon = false;
private boolean mCalledOnVisibilityAggregated = false;
private boolean mCalledDispatchStartTemporaryDetach = false;
private boolean mCalledDispatchFinishTemporaryDetach = false;
@@ -614,13 +614,13 @@
}
@Override
- public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
- mCalledOnResolvePointerIcon = true;
- return super.onResolvePointerIcon(event, pointerIndex);
+ public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
+ mCalledGetPointerIcon = true;
+ return super.getPointerIcon(event, x, y);
}
- public boolean hasCalledOnResolvePointerIcon() {
- return mCalledOnResolvePointerIcon;
+ public boolean hasCalledGetPointerIcon() {
+ return mCalledGetPointerIcon;
}
@Override
@@ -716,7 +716,7 @@
mCalledComputeScroll = false;
mCalledDispatchKeyEventPreIme = false;
mCalledOnKeyPreIme = false;
- mCalledOnResolvePointerIcon = false;
+ mCalledGetPointerIcon = false;
mCalledOnVisibilityAggregated = false;
mCalledOnVisibilityAggregated = false;
mCalledDispatchStartTemporaryDetach = false;
diff --git a/tests/tests/view/src/android/view/cts/NumberPickerTest.java b/tests/tests/view/src/android/view/cts/NumberPickerTest.java
deleted file mode 100644
index 2e2733e..0000000
--- a/tests/tests/view/src/android/view/cts/NumberPickerTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.view.cts;
-
-import android.test.AndroidTestCase;
-import android.widget.NumberPicker;
-
-public class NumberPickerTest extends AndroidTestCase {
-
- public void testSetDisplayedValues1() throws Exception {
- NumberPicker numberPicker = new NumberPicker(getContext());
- numberPicker.setMinValue(10);
- numberPicker.setMaxValue(12);
- numberPicker.setDisplayedValues(new String[]{"One", "Two", "Three"});
- }
-
- public void testSetDisplayedValues2() throws Exception {
- NumberPicker numberPicker = new NumberPicker(getContext());
- numberPicker.setMinValue(10);
- numberPicker.setMaxValue(14);
- try {
- numberPicker.setDisplayedValues(new String[]{"One", "Two", "Three"});
- fail("The size of the displayed values array must be equal to the selectable numbers!");
- } catch (Exception e) {
- /* expected */
- }
- }
-}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index d3ff57d..3f667f5 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -377,73 +377,73 @@
getInstrumentation().sendPointerSync(event);
getInstrumentation().waitForIdleSync();
- assertTrue(view.hasCalledOnResolvePointerIcon());
+ assertTrue(view.hasCalledGetPointerIcon());
final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view);
- assertFalse(view2.hasCalledOnResolvePointerIcon());
+ assertFalse(view2.hasCalledGetPointerIcon());
}
- public void testAccessPointerIcon() {
+ public void testAccessPointerShape() {
View view = mActivity.findViewById(R.id.pointer_icon_layout);
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE,
view.getX(), view.getY(), 0);
- // First view has pointerIcon="help"
- assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP),
- view.onResolvePointerIcon(event, 0));
+ // First view has pointerShape="help"
+ assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.STYLE_HELP),
+ view.getPointerIcon(event, 0, 0));
- // Second view inherits pointerIcon="crosshair" from the parent
+ // Second view inherits pointerShape="crosshair" from the parent
event.setLocation(0, 21);
- assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_CROSSHAIR),
- view.onResolvePointerIcon(event, 0));
+ assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.STYLE_CROSSHAIR),
+ view.getPointerIcon(event, 0, 21));
- // Third view has custom pointer icon defined in a resource.
+ // Third view has custom pointer shape defined in a resource.
event.setLocation(0, 41);
- assertNotNull(view.onResolvePointerIcon(event, 0));
+ assertNotNull(view.getPointerIcon(event, 0, 41));
- // Parent view has pointerIcon="crosshair"
+ // Parent view has pointerShape="crosshair"
event.setLocation(0, 61);
- assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_CROSSHAIR),
- view.onResolvePointerIcon(event, 0));
+ assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.STYLE_CROSSHAIR),
+ view.getPointerIcon(event, 0, 61));
- // Outside of the parent view, no pointer icon defined.
+ // Outside of the parent view, no pointer shape defined.
event.setLocation(0, 71);
- assertNull(view.onResolvePointerIcon(event, 0));
+ assertNull(view.getPointerIcon(event, 0, 71));
- view.setPointerIcon(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT));
- assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_TEXT),
- view.onResolvePointerIcon(event, 0));
+ view.setPointerIcon(PointerIcon.getSystemIcon(mActivity, PointerIcon.STYLE_TEXT));
+ assertEquals(PointerIcon.getSystemIcon(mActivity, PointerIcon.STYLE_TEXT),
+ view.getPointerIcon(event, 0,71));
event.recycle();
}
public void testCreatePointerIcons() {
- assertSystemPointerIcon(PointerIcon.TYPE_NULL);
- assertSystemPointerIcon(PointerIcon.TYPE_DEFAULT);
- assertSystemPointerIcon(PointerIcon.TYPE_ARROW);
- assertSystemPointerIcon(PointerIcon.TYPE_CONTEXT_MENU);
- assertSystemPointerIcon(PointerIcon.TYPE_HAND);
- assertSystemPointerIcon(PointerIcon.TYPE_HELP);
- assertSystemPointerIcon(PointerIcon.TYPE_WAIT);
- assertSystemPointerIcon(PointerIcon.TYPE_CELL);
- assertSystemPointerIcon(PointerIcon.TYPE_CROSSHAIR);
- assertSystemPointerIcon(PointerIcon.TYPE_TEXT);
- assertSystemPointerIcon(PointerIcon.TYPE_VERTICAL_TEXT);
- assertSystemPointerIcon(PointerIcon.TYPE_ALIAS);
- assertSystemPointerIcon(PointerIcon.TYPE_COPY);
- assertSystemPointerIcon(PointerIcon.TYPE_NO_DROP);
- assertSystemPointerIcon(PointerIcon.TYPE_ALL_SCROLL);
- assertSystemPointerIcon(PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW);
- assertSystemPointerIcon(PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW);
- assertSystemPointerIcon(PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW);
- assertSystemPointerIcon(PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW);
- assertSystemPointerIcon(PointerIcon.TYPE_ZOOM_IN);
- assertSystemPointerIcon(PointerIcon.TYPE_ZOOM_OUT);
- assertSystemPointerIcon(PointerIcon.TYPE_GRAB);
+ assertSystemPointerIcon(PointerIcon.STYLE_NULL);
+ assertSystemPointerIcon(PointerIcon.STYLE_DEFAULT);
+ assertSystemPointerIcon(PointerIcon.STYLE_ARROW);
+ assertSystemPointerIcon(PointerIcon.STYLE_CONTEXT_MENU);
+ assertSystemPointerIcon(PointerIcon.STYLE_HAND);
+ assertSystemPointerIcon(PointerIcon.STYLE_HELP);
+ assertSystemPointerIcon(PointerIcon.STYLE_WAIT);
+ assertSystemPointerIcon(PointerIcon.STYLE_CELL);
+ assertSystemPointerIcon(PointerIcon.STYLE_CROSSHAIR);
+ assertSystemPointerIcon(PointerIcon.STYLE_TEXT);
+ assertSystemPointerIcon(PointerIcon.STYLE_VERTICAL_TEXT);
+ assertSystemPointerIcon(PointerIcon.STYLE_ALIAS);
+ assertSystemPointerIcon(PointerIcon.STYLE_COPY);
+ assertSystemPointerIcon(PointerIcon.STYLE_NO_DROP);
+ assertSystemPointerIcon(PointerIcon.STYLE_ALL_SCROLL);
+ assertSystemPointerIcon(PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW);
+ assertSystemPointerIcon(PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW);
+ assertSystemPointerIcon(PointerIcon.STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW);
+ assertSystemPointerIcon(PointerIcon.STYLE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW);
+ assertSystemPointerIcon(PointerIcon.STYLE_ZOOM_IN);
+ assertSystemPointerIcon(PointerIcon.STYLE_ZOOM_OUT);
+ assertSystemPointerIcon(PointerIcon.STYLE_GRAB);
- assertNotNull(PointerIcon.load(mResources, R.drawable.custom_pointer_icon));
+ assertNotNull(PointerIcon.loadCustomIcon(mResources, R.drawable.custom_pointer_icon));
Bitmap bitmap = BitmapFactory.decodeResource(mResources, R.drawable.icon_blue);
- assertNotNull(PointerIcon.create(bitmap, 0, 0));
+ assertNotNull(PointerIcon.createCustomIcon(bitmap, 0, 0));
}
private void assertSystemPointerIcon(int style) {
@@ -3876,7 +3876,7 @@
assertFalse(view.hasPointerCapture());
- view.requestPointerCapture();
+ view.setPointerCapture();
assertTrue(view.hasPointerCapture());
getInstrumentation().sendPointerSync(dummyMotion);
getInstrumentation().waitForIdleSync();
@@ -3895,7 +3895,7 @@
});
getInstrumentation().waitForIdleSync();
- view.requestPointerCapture();
+ view.setPointerCapture();
assertTrue(view.hasPointerCapture());
assertFalse(view2.hasPointerCapture());
@@ -3905,7 +3905,7 @@
assertFalse(view2.hasCalledOnHoverEvent());
view.reset();
- view2.requestPointerCapture();
+ view2.setPointerCapture();
assertFalse(view.hasPointerCapture());
assertTrue(view2.hasPointerCapture());
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index 96f10fc..914ac54 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -26,7 +26,8 @@
android-common \
ctsdeviceutil \
ctstestrunner \
- platform-test-annotations
+ platform-test-annotations \
+ android-support-test
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 224966d..167a3aa 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -92,9 +92,25 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.cts.SpinnerCtsActivity"
+ android:label="SpinnerCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.widget.cts.ToolbarCtsActivity"
- android:theme="@android:style/Theme.Material.Light.NoActionBar"
- android:label="ToolbarCtsActivity">
+ android:theme="@android:style/Theme.Material.Light.NoActionBar"
+ android:label="ToolbarCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.ActionMenuViewCtsActivity"
+ android:label="ActionMenuViewCtsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -388,6 +404,54 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.cts.DatePickerCtsActivity"
+ android:label="DatePickerCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.SearchViewCtsActivity"
+ android:label="SearchViewCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.ImageButtonCtsActivity"
+ android:label="ImageButtonCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.NumberPickerCtsActivity"
+ android:label="NumberPickerCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.CheckBoxCtsActivity"
+ android:label="CheckBoxCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.cts.RadioButtonCtsActivity"
+ android:label="CheckBoxCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.app.ActivityGroup"
android:label="ActivityGroup" />
diff --git a/tests/tests/widget/res/drawable/blue_fill.xml b/tests/tests/widget/res/drawable/blue_fill.xml
index 5a24f08..383e7db 100644
--- a/tests/tests/widget/res/drawable/blue_fill.xml
+++ b/tests/tests/widget/res/drawable/blue_fill.xml
@@ -17,5 +17,5 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="#0000FF" />
+ <solid android:color="#00F" />
</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/green_fill.xml b/tests/tests/widget/res/drawable/green_fill.xml
new file mode 100644
index 0000000..76c1101
--- /dev/null
+++ b/tests/tests/widget/res/drawable/green_fill.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#0F0" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/linear_layout_divider_magenta.xml b/tests/tests/widget/res/drawable/linear_layout_divider_magenta.xml
new file mode 100644
index 0000000..2dbd654
--- /dev/null
+++ b/tests/tests/widget/res/drawable/linear_layout_divider_magenta.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#F0F" />
+ <size
+ android:width="@dimen/linear_layout_divider_size"
+ android:height="@dimen/linear_layout_divider_size" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/linear_layout_divider_red.xml b/tests/tests/widget/res/drawable/linear_layout_divider_red.xml
new file mode 100644
index 0000000..56e88ef
--- /dev/null
+++ b/tests/tests/widget/res/drawable/linear_layout_divider_red.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#F00" />
+ <size
+ android:width="@dimen/linear_layout_divider_size"
+ android:height="@dimen/linear_layout_divider_size" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/magenta_fill.xml b/tests/tests/widget/res/drawable/magenta_fill.xml
index cbb594f..8b6da76 100644
--- a/tests/tests/widget/res/drawable/magenta_fill.xml
+++ b/tests/tests/widget/res/drawable/magenta_fill.xml
@@ -17,5 +17,5 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="#FF00FF" />
+ <solid android:color="#F0F" />
</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/red_fill.xml b/tests/tests/widget/res/drawable/red_fill.xml
index e443240..8baf5b6 100644
--- a/tests/tests/widget/res/drawable/red_fill.xml
+++ b/tests/tests/widget/res/drawable/red_fill.xml
@@ -17,5 +17,5 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="#8F00" />
+ <solid android:color="#F00" />
</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/red_translucent_fill.xml b/tests/tests/widget/res/drawable/red_translucent_fill.xml
new file mode 100644
index 0000000..edfbfa0
--- /dev/null
+++ b/tests/tests/widget/res/drawable/red_translucent_fill.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#80FF0000" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/yellow_fill.xml b/tests/tests/widget/res/drawable/yellow_fill.xml
index 3bd8097..44f88c4 100644
--- a/tests/tests/widget/res/drawable/yellow_fill.xml
+++ b/tests/tests/widget/res/drawable/yellow_fill.xml
@@ -17,5 +17,5 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="#FFFF00" />
+ <solid android:color="#FF0" />
</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/actionmenuview_layout.xml b/tests/tests/widget/res/layout/actionmenuview_layout.xml
new file mode 100644
index 0000000..5d2895e
--- /dev/null
+++ b/tests/tests/widget/res/layout/actionmenuview_layout.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button" />
+
+ <ActionMenuView
+ android:id="@+id/action_menu_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
+
diff --git a/tests/tests/widget/res/layout/autocompletetextview_layout.xml b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
index 27eccab..8e023a1 100644
--- a/tests/tests/widget/res/layout/autocompletetextview_layout.xml
+++ b/tests/tests/widget/res/layout/autocompletetextview_layout.xml
@@ -24,10 +24,11 @@
android:layout_height="wrap_content"
android:text="@string/notify" />
- <android.widget.cts.AutoCompleteTextViewNoIme android:id="@+id/autocompletetv_edit"
- android:completionThreshold="1"
- android:completionHint="@string/tabs_1"
+ <android.widget.cts.AutoCompleteTextViewNoIme
+ android:id="@+id/autocompletetv_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:completionThreshold="1"
+ android:completionHint="@string/tabs_1"
android:inputType="none"/>
</LinearLayout>
diff --git a/tests/tests/widget/res/layout/calendarview_layout.xml b/tests/tests/widget/res/layout/calendarview_layout.xml
index 3bc5e47..507d48e 100644
--- a/tests/tests/widget/res/layout/calendarview_layout.xml
+++ b/tests/tests/widget/res/layout/calendarview_layout.xml
@@ -17,6 +17,7 @@
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
diff --git a/tests/tests/widget/res/layout/checkbox_layout.xml b/tests/tests/widget/res/layout/checkbox_layout.xml
index a1f1718..c922436 100644
--- a/tests/tests/widget/res/layout/checkbox_layout.xml
+++ b/tests/tests/widget/res/layout/checkbox_layout.xml
@@ -14,12 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <CheckBox android:id="@+id/check_box"
+ <CheckBox
+ android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
diff --git a/tests/tests/widget/res/layout/checkedtextview_layout.xml b/tests/tests/widget/res/layout/checkedtextview_layout.xml
index d5b9c1f..fbee93e 100644
--- a/tests/tests/widget/res/layout/checkedtextview_layout.xml
+++ b/tests/tests/widget/res/layout/checkedtextview_layout.xml
@@ -14,20 +14,22 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <ListView android:id="@+id/checkedtextview_listview"
- android:orientation="vertical"
+ <ListView
+ android:id="@+id/checkedtextview_listview"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- </ListView>
+ android:layout_height="0dip"
+ android:layout_weight="1" />
- <CheckedTextView android:id="@+id/checkedtextview_test"
- android:orientation="vertical"
+ <CheckedTextView
+ android:id="@+id/checkedtextview_test"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- </CheckedTextView>
+ android:layout_height="wrap_content"
+ android:text="@string/hello_world" />
</LinearLayout>
diff --git a/tests/tests/widget/res/layout/datepicker_layout.xml b/tests/tests/widget/res/layout/datepicker_layout.xml
index 925674c..9857440 100644
--- a/tests/tests/widget/res/layout/datepicker_layout.xml
+++ b/tests/tests/widget/res/layout/datepicker_layout.xml
@@ -14,14 +14,29 @@
limitations under the License.
-->
-<RelativeLayout
+<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- <DatePicker
- android:id="@+id/datePicker_dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true" />
+ android:layout_height="match_parent"
+ android:fillViewport="true">
-</RelativeLayout>
+ <LinearLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <DatePicker
+ android:id="@+id/date_picker_calendar_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:datePickerMode="calendar" />
+
+ <DatePicker
+ android:id="@+id/date_picker_spinner_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:datePickerMode="spinner" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/tests/widget/res/layout/imagebutton_layout.xml b/tests/tests/widget/res/layout/imagebutton_layout.xml
new file mode 100644
index 0000000..f59f669
--- /dev/null
+++ b/tests/tests/widget/res/layout/imagebutton_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ImageButton
+ android:id="@+id/image_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/icon_red" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/imagebutton_test.xml b/tests/tests/widget/res/layout/imagebutton_test.xml
deleted file mode 100644
index 7d4b691..0000000
--- a/tests/tests/widget/res/layout/imagebutton_test.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2008 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.
- -->
-<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/imagebutton"
- android:layout_width="96px"
- android:layout_height="76px"
- android:soundEffectsEnabled="false"
-/>
-
diff --git a/tests/tests/widget/res/layout/linearlayout_layout.xml b/tests/tests/widget/res/layout/linearlayout_layout.xml
index 8881552..11d2a71 100644
--- a/tests/tests/widget/res/layout/linearlayout_layout.xml
+++ b/tests/tests/widget/res/layout/linearlayout_layout.xml
@@ -14,125 +14,228 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/linearlayout_root"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/linearlayout_root"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
- <LinearLayout android:id="@+id/horizontal"
- android:orientation="horizontal"
+ <LinearLayout
+ android:id="@+id/horizontal"
android:layout_width="wrap_content"
android:layout_height="100dip"
- android:background="#FF909090">
+ android:orientation="horizontal"
+ android:background="#888">
- <TextView android:id="@+id/gravity_top"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/gravity_top"
android:layout_width="wrap_content"
android:layout_height="50dip"
android:layout_gravity="top"
- android:text="@string/horizontal_text_1"/>
+ android:background="#0F0"
+ android:text="@string/horizontal_text_1" />
- <TextView android:id="@+id/gravity_center_vertical"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/gravity_center_vertical"
android:layout_width="wrap_content"
android:layout_height="50dip"
android:layout_gravity="center_vertical"
- android:text="@string/horizontal_text_2"/>
+ android:background="#0F0"
+ android:text="@string/horizontal_text_2" />
- <TextView android:id="@+id/gravity_bottom"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/gravity_bottom"
android:layout_width="wrap_content"
android:layout_height="50dip"
android:layout_gravity="bottom"
- android:text="@string/horizontal_text_3"/>
+ android:background="#0F0"
+ android:text="@string/horizontal_text_3" />
</LinearLayout>
- <LinearLayout android:id="@+id/vertical"
- android:orientation="vertical"
+ <LinearLayout
+ android:id="@+id/vertical"
android:layout_width="100dip"
android:layout_height="wrap_content"
- android:background="#FFFF0909">
+ android:orientation="vertical"
+ android:background="#F00">
- <TextView android:id="@+id/gravity_left"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/gravity_left"
android:layout_width="wrap_content"
android:layout_height="20dip"
android:layout_gravity="left"
- android:text="@string/vertical_text_1"/>
+ android:background="#0F0"
+ android:text="@string/vertical_text_1" />
- <TextView android:id="@+id/gravity_center_horizontal"
- android:background="#FF0000FF"
+ <TextView
+ android:id="@+id/gravity_center_horizontal"
android:layout_width="wrap_content"
android:layout_height="20dip"
android:layout_gravity="center_horizontal"
- android:text="@string/vertical_text_2"/>
+ android:background="#00F"
+ android:text="@string/vertical_text_2" />
- <TextView android:id="@+id/gravity_right"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/gravity_right"
android:layout_width="wrap_content"
android:layout_height="20dip"
android:layout_gravity="right"
- android:text="@string/vertical_text_3"/>
+ android:background="#0F0"
+ android:text="@string/vertical_text_3" />
</LinearLayout>
- <LinearLayout android:id="@+id/weightsum"
+ <LinearLayout
+ android:id="@+id/weightsum"
+ android:layout_width="100dip"
+ android:layout_height="100dip"
android:orientation="horizontal"
android:weightSum="1.0"
android:baselineAligned="false"
- android:layout_width="100dip"
- android:layout_height="100dip"
- android:background="#FF909090">
+ android:background="#888">
- <TextView android:id="@+id/weight_0_2"
- android:background="#FF0000FF"
+ <TextView
+ android:id="@+id/weight_0_2"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.2"
- android:text="@string/horizontal_text_1"/>
+ android:background="#00F"
+ android:text="@string/horizontal_text_1" />
- <TextView android:id="@+id/weight_0_5"
- android:background="#FFF00F0F"
+ <TextView
+ android:id="@+id/weight_0_5"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.5"
- android:text="@string/horizontal_text_2"/>
+ android:background="#F00"
+ android:text="@string/horizontal_text_2" />
- <TextView android:id="@+id/weight_0_3"
- android:background="#FF0000FF"
+ <TextView
+ android:id="@+id/weight_0_3"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.3"
- android:text="@string/horizontal_text_3"/>
+ android:background="#00F"
+ android:text="@string/horizontal_text_3" />
</LinearLayout>
- <LinearLayout android:id="@+id/baseline_aligned_child_index"
+ <LinearLayout
+ android:id="@+id/weightsum_vertical"
+ android:layout_width="100dip"
+ android:layout_height="100dip"
android:orientation="vertical"
- android:baselineAlignedChildIndex="1"
+ android:weightSum="1.0"
+ android:baselineAligned="false"
+ android:background="#888">
+
+ <TextView
+ android:id="@+id/weight_0_1"
+ android:layout_width="wrap_content"
+ android:layout_height="0dip"
+ android:layout_weight="0.1"
+ android:background="#00F"
+ android:text="@string/vertical_text_1" />
+
+ <TextView
+ android:id="@+id/weight_0_4"
+ android:layout_width="wrap_content"
+ android:layout_height="0dip"
+ android:layout_weight="0.4"
+ android:background="#F00"
+ android:text="@string/vertical_text_2" />
+
+ <TextView
+ android:id="@+id/weight_0_5"
+ android:layout_width="wrap_content"
+ android:layout_height="0dip"
+ android:layout_weight="0.5"
+ android:background="#00F"
+ android:text="@string/vertical_text_3" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/baseline_aligned_child_index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="#FFFF0909">
+ android:orientation="vertical"
+ android:baselineAlignedChildIndex="1"
+ android:background="#F00">
- <TextView android:id="@+id/textview1"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/textview1"
android:layout_width="wrap_content"
android:layout_height="20dip"
android:layout_gravity="left"
- android:text="@string/vertical_text_1"/>
+ android:background="#0F0"
+ android:text="@string/vertical_text_1" />
- <TextView android:id="@+id/textview2"
- android:background="#FF0000FF"
+ <TextView
+ android:id="@+id/textview2"
android:layout_width="wrap_content"
android:layout_height="20dip"
android:layout_gravity="center_horizontal"
- android:text="@string/vertical_text_2"/>
+ android:background="#00F"
+ android:text="@string/vertical_text_2" />
- <TextView android:id="@+id/textview3"
- android:background="#FF00FF00"
+ <TextView
+ android:id="@+id/textview3"
android:layout_width="wrap_content"
android:layout_height="20dip"
android:layout_gravity="right"
- android:text="@string/vertical_text_3"/>
+ android:background="#0F0"
+ android:text="@string/vertical_text_3" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/vertical_with_divider"
+ android:layout_width="100px"
+ android:layout_height="100px"
+ android:orientation="vertical"
+ android:background="#FF0"
+ android:showDividers="middle"
+ android:divider="@drawable/linear_layout_divider_red"
+ android:dividerPadding="@dimen/linear_layout_divider_padding">
+
+ <View
+ android:id="@+id/child1"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="0.5"
+ android:background="#00F" />
+
+ <View
+ android:id="@+id/child2"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="0.5"
+ android:background="#0F0" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/horizontal_with_divider"
+ android:layout_width="100px"
+ android:layout_height="100px"
+ android:orientation="horizontal"
+ android:background="#FF0"
+ android:showDividers="middle"
+ android:divider="@drawable/linear_layout_divider_red"
+ android:dividerPadding="@dimen/linear_layout_divider_padding">
+
+ <View
+ android:id="@+id/child1"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="0.5"
+ android:background="#00F" />
+
+ <View
+ android:id="@+id/child2"
+ android:layout_width="0dip"
+ android:layout_height="match_parent"
+ android:layout_weight="0.5"
+ android:background="#0F0" />
+
</LinearLayout>
</LinearLayout>
diff --git a/tests/tests/widget/res/layout/numberpicker_layout.xml b/tests/tests/widget/res/layout/numberpicker_layout.xml
new file mode 100644
index 0000000..2e370d8
--- /dev/null
+++ b/tests/tests/widget/res/layout/numberpicker_layout.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <NumberPicker
+ android:id="@+id/number_picker"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/radiobutton_layout.xml b/tests/tests/widget/res/layout/radiobutton_layout.xml
new file mode 100644
index 0000000..23c1839
--- /dev/null
+++ b/tests/tests/widget/res/layout/radiobutton_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <RadioButton
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hello_world" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/searchview_layout.xml b/tests/tests/widget/res/layout/searchview_layout.xml
new file mode 100644
index 0000000..b8705e0
--- /dev/null
+++ b/tests/tests/widget/res/layout/searchview_layout.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <SearchView
+ android:id="@+id/search_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <SearchView
+ android:id="@+id/search_view_with_defaults"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxWidth="@dimen/search_view_max_width"
+ android:iconifiedByDefault="false"
+ android:queryHint="@string/search_query_hint"
+ android:inputType="textCapCharacters"
+ android:imeOptions="actionDone" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/searchview_suggestion_item.xml b/tests/tests/widget/res/layout/searchview_suggestion_item.xml
new file mode 100644
index 0000000..91f02f5
--- /dev/null
+++ b/tests/tests/widget/res/layout/searchview_suggestion_item.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/search_view_suggestion_row_height"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" />
diff --git a/tests/tests/widget/res/layout/simple_spinner_item_layout.xml b/tests/tests/widget/res/layout/simple_spinner_item_layout.xml
new file mode 100644
index 0000000..512b138
--- /dev/null
+++ b/tests/tests/widget/res/layout/simple_spinner_item_layout.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ style="?android:attr/spinnerItemStyle"
+ android:singleLine="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="marquee"
+ android:textAlignment="inherit"/>
diff --git a/tests/tests/widget/res/layout/spinner_layout.xml b/tests/tests/widget/res/layout/spinner_layout.xml
new file mode 100644
index 0000000..43a6411
--- /dev/null
+++ b/tests/tests/widget/res/layout/spinner_layout.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+
+ <LinearLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <Spinner
+ android:id="@+id/spinner_dropdown_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:spinnerMode="dropdown"
+ android:prompt="@string/text_view_hello" />
+
+ <Spinner
+ android:id="@+id/spinner_dialog_mode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:spinnerMode="dialog"
+ android:prompt="@string/text_view_hello" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/tests/widget/res/layout/switch_layout.xml b/tests/tests/widget/res/layout/switch_layout.xml
index 12e10d2..880c6df 100644
--- a/tests/tests/widget/res/layout/switch_layout.xml
+++ b/tests/tests/widget/res/layout/switch_layout.xml
@@ -15,11 +15,31 @@
~ limitations under the License
-->
-<Switch xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/switch_view"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <Switch
+ android:id="@+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:thumbTint="@android:color/white"
android:thumbTintMode="src_over"
android:trackTint="@android:color/black"
android:trackTintMode="src_atop" />
+
+ <Switch
+ android:id="@+id/switch2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:thumb="@drawable/icon_blue"
+ android:track="@drawable/red_translucent_fill" />
+
+ <Switch
+ android:id="@+id/switch3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/values/dimens.xml b/tests/tests/widget/res/values/dimens.xml
index 3690039..447abc3 100644
--- a/tests/tests/widget/res/values/dimens.xml
+++ b/tests/tests/widget/res/values/dimens.xml
@@ -15,4 +15,25 @@
-->
<resources>
<dimen name="popup_row_height">48dp</dimen>
+
+ <dimen name="switch_padding">24dp</dimen>
+ <dimen name="switch_thumb_text_padding">12dp</dimen>
+ <dimen name="switch_min_width">160dp</dimen>
+ <dimen name="switch_min_width2">200dp</dimen>
+
+ <dimen name="autocomplete_textview_dropdown_height">120dp</dimen>
+ <dimen name="autocomplete_textview_dropdown_width">160dp</dimen>
+ <dimen name="autocomplete_textview_dropdown_offset_h">24dp</dimen>
+ <dimen name="autocomplete_textview_dropdown_offset_v">32dp</dimen>
+
+ <dimen name="spinner_dropdown_width">200dp</dimen>
+ <dimen name="spinner_dropdown_offset_h">64dp</dimen>
+ <dimen name="spinner_dropdown_offset_v">48dp</dimen>
+
+ <dimen name="search_view_max_width">160dp</dimen>
+ <dimen name="search_view_max_width2">200dp</dimen>
+ <dimen name="search_view_suggestion_row_height">48dp</dimen>
+
+ <dimen name="linear_layout_divider_size">10px</dimen>
+ <dimen name="linear_layout_divider_padding">8px</dimen>
</resources>
\ No newline at end of file
diff --git a/tests/tests/widget/res/values/strings.xml b/tests/tests/widget/res/values/strings.xml
index 63ceffa..5c954b8 100644
--- a/tests/tests/widget/res/values/strings.xml
+++ b/tests/tests/widget/res/values/strings.xml
@@ -193,4 +193,6 @@
<string name="toolbar_subtitle">Toolbar subtitle</string>
<string name="toolbar_navigation">Toolbar navigation</string>
<string name="toolbar_logo">Toolbar logo</string>
+
+ <string name="search_query_hint">query hint</string>
</resources>
diff --git a/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java
new file mode 100644
index 0000000..1b58b63
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ActionMenuViewCtsActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ActionMenuView;
+
+/**
+ * A minimal application for {@link ActionMenuView} test.
+ */
+public class ActionMenuViewCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.actionmenuview_layout);
+ }
+}
+
diff --git a/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java b/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java
new file mode 100644
index 0000000..6de7c39
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ActionMenuViewTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Instrumentation;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ActionMenuView;
+import android.widget.Toolbar;
+import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.ViewTestUtils;
+
+import static org.mockito.Mockito.*;
+
+@MediumTest
+public class ActionMenuViewTest
+ extends ActivityInstrumentationTestCase2<ActionMenuViewCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private ActionMenuViewCtsActivity mActivity;
+ private ActionMenuView mActionMenuView;
+
+ public ActionMenuViewTest() {
+ super("android.widget.cts", ActionMenuViewCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mActionMenuView = (ActionMenuView) mActivity.findViewById(R.id.action_menu_view);
+ }
+
+ public void testConstructor() {
+ new ActionMenuView(mActivity);
+
+ new ActionMenuView(mActivity, null);
+ }
+
+ public void testMenuContent() {
+ final Menu menu = mActionMenuView.getMenu();
+ assertNotNull(menu);
+
+ mInstrumentation.runOnMainSync(
+ () -> mActivity.getMenuInflater().inflate(
+ R.menu.toolbar_menu, menu));
+
+ assertEquals(6, menu.size());
+ assertEquals(R.id.action_highlight, menu.getItem(0).getItemId());
+ assertEquals(R.id.action_edit, menu.getItem(1).getItemId());
+ assertEquals(R.id.action_delete, menu.getItem(2).getItemId());
+ assertEquals(R.id.action_ignore, menu.getItem(3).getItemId());
+ assertEquals(R.id.action_share, menu.getItem(4).getItemId());
+ assertEquals(R.id.action_print, menu.getItem(5).getItemId());
+
+ ActionMenuView.OnMenuItemClickListener menuItemClickListener =
+ mock(ActionMenuView.OnMenuItemClickListener.class);
+ mActionMenuView.setOnMenuItemClickListener(menuItemClickListener);
+
+ menu.performIdentifierAction(R.id.action_highlight, 0);
+ verify(menuItemClickListener, times(1)).onMenuItemClick(
+ menu.findItem(R.id.action_highlight));
+
+ menu.performIdentifierAction(R.id.action_share, 0);
+ verify(menuItemClickListener, times(1)).onMenuItemClick(
+ menu.findItem(R.id.action_share));
+ }
+
+ public void testMenuOverflowShowHide() {
+ // Inflate menu and check that we're not showing overflow menu yet
+ mInstrumentation.runOnMainSync(
+ () -> mActivity.getMenuInflater().inflate(
+ R.menu.toolbar_menu, mActionMenuView.getMenu()));
+ assertFalse(mActionMenuView.isOverflowMenuShowing());
+
+ // Ask to show overflow menu and check that it's showing
+ mInstrumentation.runOnMainSync(() -> mActionMenuView.showOverflowMenu());
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mActionMenuView.isOverflowMenuShowing());
+
+ // Ask to hide the overflow menu and check that it's not showing
+ mInstrumentation.runOnMainSync(() -> mActionMenuView.hideOverflowMenu());
+ mInstrumentation.waitForIdleSync();
+ assertFalse(mActionMenuView.isOverflowMenuShowing());
+ }
+
+ public void testMenuOverflowSubmenu() {
+ // Inflate menu and check that we're not showing overflow menu yet
+ mInstrumentation.runOnMainSync(
+ () -> mActivity.getMenuInflater().inflate(
+ R.menu.toolbar_menu, mActionMenuView.getMenu()));
+ assertFalse(mActionMenuView.isOverflowMenuShowing());
+
+ // Ask to show overflow menu and check that it's showing
+ mInstrumentation.runOnMainSync(() -> mActionMenuView.showOverflowMenu());
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mActionMenuView.isOverflowMenuShowing());
+
+ // Register a mock menu item click listener on the toolbar
+ ActionMenuView.OnMenuItemClickListener menuItemClickListener =
+ mock(ActionMenuView.OnMenuItemClickListener.class);
+ mActionMenuView.setOnMenuItemClickListener(menuItemClickListener);
+
+ final Menu menu = mActionMenuView.getMenu();
+
+ // Ask to "perform" the share action and check that the menu click listener has
+ // been notified
+ mInstrumentation.runOnMainSync(() -> menu.performIdentifierAction(R.id.action_share, 0));
+ verify(menuItemClickListener, times(1)).onMenuItemClick(
+ menu.findItem(R.id.action_share));
+
+ // Ask to dismiss all the popups and check that we're not showing the overflow menu
+ mInstrumentation.runOnMainSync(() -> mActionMenuView.dismissPopupMenus());
+ mInstrumentation.waitForIdleSync();
+ assertFalse(mActionMenuView.isOverflowMenuShowing());
+ }
+
+ public void testMenuOverflowIcon() {
+ // Inflate menu and check that we're not showing overflow menu yet
+ mInstrumentation.runOnMainSync(
+ () -> mActivity.getMenuInflater().inflate(
+ R.menu.toolbar_menu, mActionMenuView.getMenu()));
+
+ final Drawable overflowIcon = mActivity.getDrawable(R.drawable.icon_red);
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mActionMenuView,
+ () -> mActionMenuView.setOverflowIcon(overflowIcon));
+
+ final Drawable toolbarOverflowIcon = mActionMenuView.getOverflowIcon();
+ TestUtils.assertAllPixelsOfColor("Overflow icon is red", toolbarOverflowIcon,
+ toolbarOverflowIcon.getIntrinsicWidth(), toolbarOverflowIcon.getIntrinsicHeight(),
+ true, Color.RED, 1, false);
+ }
+
+ public void testPopupTheme() {
+ mInstrumentation.runOnMainSync(() -> {
+ mActivity.getMenuInflater().inflate(R.menu.toolbar_menu, mActionMenuView.getMenu());
+ mActionMenuView.setPopupTheme(R.style.ToolbarPopupTheme_Test);
+ });
+ assertEquals(R.style.ToolbarPopupTheme_Test, mActionMenuView.getPopupTheme());
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
index eb22d6b..5a8454fe 100644
--- a/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AutoCompleteTextViewTest.java
@@ -16,21 +16,22 @@
package android.widget.cts;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.app.Activity;
import android.app.Instrumentation;
import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.cts.util.PollingCheck;
+import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Xml;
import android.view.KeyCharacterMap;
@@ -40,37 +41,30 @@
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
+import android.widget.AutoCompleteTextView.Validator;
import android.widget.Filter;
import android.widget.Filterable;
-import android.widget.AutoCompleteTextView.Validator;
+import android.widget.cts.util.TestUtils;
+import org.xmlpull.v1.XmlPullParser;
-import java.io.IOException;
+import static org.mockito.Mockito.*;
+@MediumTest
public class AutoCompleteTextViewTest extends
ActivityInstrumentationTestCase2<AutoCompleteCtsActivity> {
+ private final static String[] WORDS =
+ new String[] { "testOne", "testTwo", "testThree", "testFour" };
+ private final static String STRING_TEST = "To be tested";
+ private final static String STRING_VALIDATED = "String Validated";
+ private final static String STRING_CHECK = "To be checked";
- /**
- * Instantiates a new text view test.
- */
- public AutoCompleteTextViewTest() {
- super("android.widget.cts", AutoCompleteCtsActivity.class);
- }
-
- /** The m activity. */
private Activity mActivity;
-
- /** The m instrumentation. */
private Instrumentation mInstrumentation;
private AutoCompleteTextView mAutoCompleteTextView;
private boolean mNumeric = false;
- ArrayAdapter<String> mAdapter;
- private final String[] WORDS = new String[] { "testOne", "testTwo", "testThree", "testFour" };
- boolean isOnFilterComplete = false;
- final String STRING_TEST = "To be tested";
- final String STRING_VALIDATED = "String Validated";
- final String STRING_CHECK = "To be checked";
- final String STRING_APPEND = "and be appended";
- Validator mValidator = new Validator() {
+ private ArrayAdapter<String> mAdapter;
+
+ private final Validator mValidator = new Validator() {
public CharSequence fixText(CharSequence invalidText) {
return STRING_VALIDATED;
}
@@ -80,6 +74,36 @@
}
};
+ protected class MyTextWatcher implements TextWatcher {
+ private CharSequence mExpectedAfter;
+
+ public MyTextWatcher(CharSequence expectedAfter) {
+ mExpectedAfter = expectedAfter;
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ assertEquals(mExpectedAfter.toString(), s.toString());
+ // This watcher is expected to be notified in the middle of completion
+ assertTrue(mAutoCompleteTextView.isPerformingCompletion());
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ }
+
+ /**
+ * Instantiates a new text view test.
+ */
+ public AutoCompleteTextViewTest() {
+ super("android.widget.cts", AutoCompleteCtsActivity.class);
+ }
+
/*
* (non-Javadoc)
*
@@ -89,12 +113,8 @@
protected void setUp() throws Exception {
super.setUp();
mActivity = getActivity();
- new PollingCheck() {
- @Override
- protected boolean check() {
- return mActivity.hasWindowFocus();
- }
- }.run();
+ PollingCheck.waitFor(() -> mActivity.hasWindowFocus());
+
mInstrumentation = getInstrumentation();
mAutoCompleteTextView = (AutoCompleteTextView) mActivity
.findViewById(R.id.autocompletetv_edit);
@@ -116,20 +136,26 @@
public void testConstructor() {
XmlPullParser parser;
- // new the AutoCompleteTextView instance
new AutoCompleteTextView(mActivity);
+ new AutoCompleteTextView(mActivity, null);
+ new AutoCompleteTextView(mActivity, null, android.R.attr.autoCompleteTextViewStyle);
+ new AutoCompleteTextView(mActivity, null, 0,
+ android.R.style.Widget_Material_Light_AutoCompleteTextView);
+
+ final Resources.Theme popupTheme = mActivity.getResources().newTheme();
+ popupTheme.applyStyle(android.R.style.Theme_Material, true);
+ new AutoCompleteTextView(mActivity, null, 0,
+ android.R.style.Widget_Material_Light_AutoCompleteTextView, popupTheme);
// new the AutoCompleteTextView instance
parser = mActivity.getResources().getXml(R.layout.simple_dropdown_item_1line);
AttributeSet attributeSet = Xml.asAttributeSet(parser);
new AutoCompleteTextView(mActivity, attributeSet);
- new AutoCompleteTextView(mActivity, null);
// new the AutoCompleteTextView instance
parser = mActivity.getResources().getXml(R.layout.framelayout_layout);
attributeSet = Xml.asAttributeSet(parser);
new AutoCompleteTextView(mActivity, attributeSet, 0);
- new AutoCompleteTextView(mActivity, null, 0);
// Test constructor with null Context, in fact, previous two functions will
// finally invoke this version.
try {
@@ -145,38 +171,39 @@
new AutoCompleteTextView(mActivity, null, -1);
}
- public void testEnoughToFilter() throws Throwable {
+ public void testEnoughToFilter() {
mAutoCompleteTextView.setThreshold(3);
assertEquals(3, mAutoCompleteTextView.getThreshold());
- runTestOnUiThread(new Runnable() {
- public void run() {
- String testString = "TryToTest";
- mAutoCompleteTextView.setText(testString);
- }
- });
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("TryToTest"));
mInstrumentation.waitForIdleSync();
assertTrue(mAutoCompleteTextView.enoughToFilter());
- runTestOnUiThread(new Runnable() {
- public void run() {
- String testString = "No";
- mAutoCompleteTextView.setText(testString);
- }
- });
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("No"));
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.enoughToFilter());
}
- @UiThreadTest
public void testAccessAdapter() {
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(null));
+ assertNull(mAutoCompleteTextView.getAdapter());
+
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+ assertSame(mAdapter, mAutoCompleteTextView.getAdapter());
+
+ // Re-set adapter to null
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(null));
+ assertNull(mAutoCompleteTextView.getAdapter());
+ }
+
+ @UiThreadTest
+ public void testAccessFilter() {
MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
// Set Threshold to 4 characters
autoCompleteTextView.setThreshold(4);
- ArrayAdapter<String> adapter = null;
- autoCompleteTextView.setAdapter(adapter);
+ autoCompleteTextView.setAdapter(null);
assertNull(autoCompleteTextView.getAdapter());
assertNull(autoCompleteTextView.getFilter());
@@ -187,49 +214,51 @@
assertSame(filter, autoCompleteTextView.getFilter());
// Re-set adapter to null
- autoCompleteTextView.setAdapter(adapter);
+ autoCompleteTextView.setAdapter(null);
assertNull(autoCompleteTextView.getAdapter());
assertNull(autoCompleteTextView.getFilter());
}
- @SuppressWarnings("deprecation")
public void testAccessItemClickListener() {
- final MockOnItemClickListener testOnItemClickListener = new MockOnItemClickListener();
+ final AdapterView.OnItemClickListener mockItemClickListener =
+ mock(AdapterView.OnItemClickListener.class);
// To ensure null listener
mAutoCompleteTextView.setOnItemClickListener(null);
assertNull(mAutoCompleteTextView.getItemClickListener());
assertNull(mAutoCompleteTextView.getOnItemClickListener());
- assertNotNull(testOnItemClickListener);
- mAutoCompleteTextView.setOnItemClickListener(testOnItemClickListener);
- assertSame(testOnItemClickListener, mAutoCompleteTextView.getItemClickListener());
- assertSame(testOnItemClickListener, mAutoCompleteTextView.getOnItemClickListener());
+ mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+ assertSame(mockItemClickListener, mAutoCompleteTextView.getItemClickListener());
+ assertSame(mockItemClickListener, mAutoCompleteTextView.getOnItemClickListener());
+ verifyZeroInteractions(mockItemClickListener);
// re-clear listener by setOnItemClickListener
mAutoCompleteTextView.setOnItemClickListener(null);
assertNull(mAutoCompleteTextView.getItemClickListener());
assertNull(mAutoCompleteTextView.getOnItemClickListener());
+ verifyZeroInteractions(mockItemClickListener);
}
- @SuppressWarnings("deprecation")
public void testAccessItemSelectedListener() {
- MockOnItemSelectedListener testOnItemSelectedListener = new MockOnItemSelectedListener();
+ final AdapterView.OnItemSelectedListener mockItemSelectedListener =
+ mock(AdapterView.OnItemSelectedListener.class);
// To ensure null listener
mAutoCompleteTextView.setOnItemSelectedListener(null);
assertNull(mAutoCompleteTextView.getItemSelectedListener());
assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
- assertNotNull(testOnItemSelectedListener);
- mAutoCompleteTextView.setOnItemSelectedListener(testOnItemSelectedListener);
- assertSame(testOnItemSelectedListener, mAutoCompleteTextView.getItemSelectedListener());
- assertSame(testOnItemSelectedListener, mAutoCompleteTextView.getOnItemSelectedListener());
+ mAutoCompleteTextView.setOnItemSelectedListener(mockItemSelectedListener);
+ assertSame(mockItemSelectedListener, mAutoCompleteTextView.getItemSelectedListener());
+ assertSame(mockItemSelectedListener, mAutoCompleteTextView.getOnItemSelectedListener());
+ verifyZeroInteractions(mockItemSelectedListener);
//re-clear listener by setOnItemClickListener
mAutoCompleteTextView.setOnItemSelectedListener(null);
assertNull(mAutoCompleteTextView.getItemSelectedListener());
assertNull(mAutoCompleteTextView.getOnItemSelectedListener());
+ verifyZeroInteractions(mockItemSelectedListener);
}
@UiThreadTest
@@ -247,73 +276,130 @@
@UiThreadTest
public void testOnTextChanged() {
- MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
+ final TextWatcher mockTextWatcher = mock(TextWatcher.class);
+ mAutoCompleteTextView.addTextChangedListener(mockTextWatcher);
+ verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
+ anyInt(), anyInt(), anyInt());
- assertFalse(autoCompleteTextView.isOnTextChanged());
- assertEquals("", autoCompleteTextView.getLastChangeText());
- assertEquals("", autoCompleteTextView.getText().toString());
- assertEquals(0, autoCompleteTextView.getStart());
- assertEquals(0, autoCompleteTextView.getBefore());
- assertEquals(0, autoCompleteTextView.getAfter());
-
- autoCompleteTextView.setText(STRING_TEST);
- assertEquals(STRING_TEST, autoCompleteTextView.getText().toString());
- assertTrue(autoCompleteTextView.isOnTextChanged());
- assertEquals(STRING_TEST, autoCompleteTextView.getLastChangeText());
- assertEquals(0, autoCompleteTextView.getStart());
- assertEquals(0, autoCompleteTextView.getBefore());
- assertEquals(STRING_TEST.length(), autoCompleteTextView.getAfter());
+ mAutoCompleteTextView.setText(STRING_TEST);
+ verify(mockTextWatcher, times(1)).onTextChanged(TestUtils.sameCharSequence(STRING_TEST),
+ eq(0), eq(0), eq(STRING_TEST.length()));
// Test replacing text.
- autoCompleteTextView.resetStatus();
- autoCompleteTextView.setText(STRING_CHECK);
- assertEquals(STRING_CHECK, autoCompleteTextView.getText().toString());
- assertEquals(STRING_CHECK, autoCompleteTextView.getLastChangeText());
- assertEquals(0, autoCompleteTextView.getStart());
- assertEquals(STRING_TEST.length(), autoCompleteTextView.getBefore());
- assertEquals(STRING_CHECK.length(), autoCompleteTextView.getAfter());
+ mAutoCompleteTextView.setText(STRING_CHECK);
+ verify(mockTextWatcher, times(1)).onTextChanged(TestUtils.sameCharSequence(STRING_CHECK),
+ eq(0), eq(STRING_TEST.length()), eq(STRING_CHECK.length()));
}
- @UiThreadTest
- public void testPopupWindow() throws XmlPullParserException, IOException {
- assertFalse(mAutoCompleteTextView.isPopupShowing());
- mAutoCompleteTextView.showDropDown();
- assertTrue(mAutoCompleteTextView.isPopupShowing());
+ public void testPopupWindow() {
+ final AutoCompleteTextView.OnDismissListener mockDismissListener =
+ mock(AutoCompleteTextView.OnDismissListener.class);
+ mAutoCompleteTextView.setOnDismissListener(mockDismissListener);
- mAutoCompleteTextView.dismissDropDown();
assertFalse(mAutoCompleteTextView.isPopupShowing());
-
- mAutoCompleteTextView.showDropDown();
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.showDropDown());
assertTrue(mAutoCompleteTextView.isPopupShowing());
+ verifyZeroInteractions(mockDismissListener);
+
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.dismissDropDown());
+ assertFalse(mAutoCompleteTextView.isPopupShowing());
+ verify(mockDismissListener, times(1)).onDismiss();
+
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.showDropDown());
+ assertTrue(mAutoCompleteTextView.isPopupShowing());
+ verify(mockDismissListener, times(1)).onDismiss();
final MockValidator validator = new MockValidator();
mAutoCompleteTextView.setValidator(validator);
- mAutoCompleteTextView.requestFocus();
- mAutoCompleteTextView.showDropDown();
- assertTrue(mAutoCompleteTextView.isPopupShowing());
- mAutoCompleteTextView.setText(STRING_TEST);
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.requestFocus();
+ mAutoCompleteTextView.showDropDown();
+ mAutoCompleteTextView.setText(STRING_TEST);
+ });
assertEquals(STRING_TEST, mAutoCompleteTextView.getText().toString());
+
// clearFocus will trigger onFocusChanged, and onFocusChanged will validate the text.
- mAutoCompleteTextView.clearFocus();
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.clearFocus());
assertFalse(mAutoCompleteTextView.isPopupShowing());
assertEquals(STRING_VALIDATED, mAutoCompleteTextView.getText().toString());
+ verify(mockDismissListener, times(2)).onDismiss();
+
+ verifyNoMoreInteractions(mockDismissListener);
+ }
+
+ public void testDropDownMetrics() {
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+
+ final Resources res = mActivity.getResources();
+ final int dropDownWidth =
+ res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_width);
+ final int dropDownHeight =
+ res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_height);
+ final int dropDownOffsetHorizontal =
+ res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_h);
+ final int dropDownOffsetVertical =
+ res.getDimensionPixelSize(R.dimen.autocomplete_textview_dropdown_offset_v);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setDropDownWidth(dropDownWidth);
+ mAutoCompleteTextView.setDropDownHeight(dropDownHeight);
+ mAutoCompleteTextView.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
+ mAutoCompleteTextView.setDropDownVerticalOffset(dropDownOffsetVertical);
+
+ mAutoCompleteTextView.showDropDown();
+ });
+
+ assertEquals(dropDownWidth, mAutoCompleteTextView.getDropDownWidth());
+ assertEquals(dropDownHeight, mAutoCompleteTextView.getDropDownHeight());
+ assertEquals(dropDownOffsetHorizontal, mAutoCompleteTextView.getDropDownHorizontalOffset());
+ assertEquals(dropDownOffsetVertical, mAutoCompleteTextView.getDropDownVerticalOffset());
+ }
+
+ public void testDropDownBackground() {
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setAdapter(mAdapter));
+
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setDropDownBackgroundResource(R.drawable.blue_fill);
+ mAutoCompleteTextView.showDropDown();
+ });
+ mInstrumentation.waitForIdleSync();
+
+ Drawable dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
+ TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
+ dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+ false, Color.BLUE, 1, true);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.dismissDropDown();
+ mAutoCompleteTextView.setDropDownBackgroundDrawable(
+ mActivity.getDrawable(R.drawable.yellow_fill));
+ mAutoCompleteTextView.showDropDown();
+ });
+ mInstrumentation.waitForIdleSync();
+
+ dropDownBackground = mAutoCompleteTextView.getDropDownBackground();
+ TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
+ dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+ false, Color.YELLOW, 1, true);
}
@UiThreadTest
public void testReplaceText() {
MockAutoCompleteTextView autoCompleteTextView = new MockAutoCompleteTextView(mActivity);
+ final TextWatcher mockTextWatcher = mock(TextWatcher.class);
+ autoCompleteTextView.addTextChangedListener(mockTextWatcher);
+ verify(mockTextWatcher, never()).onTextChanged(any(CharSequence.class),
+ anyInt(), anyInt(), anyInt());
- assertEquals("", autoCompleteTextView.getText().toString());
- assertFalse(autoCompleteTextView.isOnTextChanged());
autoCompleteTextView.replaceText("Text");
assertEquals("Text", autoCompleteTextView.getText().toString());
- assertTrue(autoCompleteTextView.isOnTextChanged());
+ verify(mockTextWatcher, times(1)).onTextChanged(TestUtils.sameCharSequence("Text"),
+ eq(0), eq(0), eq("Text".length()));
- autoCompleteTextView.resetStatus();
- assertFalse(autoCompleteTextView.isOnTextChanged());
autoCompleteTextView.replaceText("Another");
assertEquals("Another", autoCompleteTextView.getText().toString());
- assertTrue(autoCompleteTextView.isOnTextChanged());
+ verify(mockTextWatcher, times(1)).onTextChanged(TestUtils.sameCharSequence("Another"),
+ eq(0), eq("Text".length()), eq("Another".length()));
}
@UiThreadTest
@@ -342,21 +428,17 @@
}
public void testGetThreshold() {
- final AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) mActivity
- .findViewById(R.id.autocompletetv_edit);
- assertNotNull(autoCompleteTextView);
-
- assertEquals(1, autoCompleteTextView.getThreshold());
- autoCompleteTextView.setThreshold(3);
- assertEquals(3, autoCompleteTextView.getThreshold());
+ assertEquals(1, mAutoCompleteTextView.getThreshold());
+ mAutoCompleteTextView.setThreshold(3);
+ assertEquals(3, mAutoCompleteTextView.getThreshold());
// Test negative value input
- autoCompleteTextView.setThreshold(-5);
- assertEquals(1, autoCompleteTextView.getThreshold());
+ mAutoCompleteTextView.setThreshold(-5);
+ assertEquals(1, mAutoCompleteTextView.getThreshold());
// Test zero
- autoCompleteTextView.setThreshold(0);
- assertEquals(1, autoCompleteTextView.getThreshold());
+ mAutoCompleteTextView.setThreshold(0);
+ assertEquals(1, mAutoCompleteTextView.getThreshold());
}
public void testAccessValidater() {
@@ -371,7 +453,7 @@
assertNull(mAutoCompleteTextView.getValidator());
}
- public void testOnFilterComplete() throws Throwable {
+ public void testOnFilterComplete() {
// Set Threshold to 4 characters
mAutoCompleteTextView.setThreshold(4);
@@ -384,22 +466,15 @@
}
// Test the filter if the input string is not long enough to threshold
- runTestOnUiThread(new Runnable() {
- public void run() {
+ mInstrumentation.runOnMainSync(() -> {
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.setText("");
mAutoCompleteTextView.requestFocus();
- }
});
mInstrumentation.sendStringSync(testString);
// onFilterComplete will close the popup.
- new PollingCheck() {
- @Override
- protected boolean check() {
- return !mAutoCompleteTextView.isPopupShowing();
- }
- }.run();
+ PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
if (mNumeric) {
// "that" in case of 12-key(NUMERIC) keyboard
@@ -408,20 +483,13 @@
testString = "that";
}
mInstrumentation.sendStringSync(testString);
- new PollingCheck() {
- @Override
- protected boolean check() {
- return !mAutoCompleteTextView.isPopupShowing();
- }
- }.run();
+ PollingCheck.waitFor(() -> !mAutoCompleteTextView.isPopupShowing());
// Test the expected filter matching scene
- runTestOnUiThread(new Runnable() {
- public void run() {
+ mInstrumentation.runOnMainSync(() -> {
mAutoCompleteTextView.setFocusable(true);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.setText("");
- }
});
if (mNumeric) {
// "test" in case of 12-key(NUMERIC) keyboard
@@ -431,20 +499,14 @@
}
assertTrue(mAutoCompleteTextView.hasFocus());
assertTrue(mAutoCompleteTextView.hasWindowFocus());
- new PollingCheck() {
- @Override
- protected boolean check() {
- return mAutoCompleteTextView.isPopupShowing();
- }
- }.run();
+ PollingCheck.waitFor(() -> mAutoCompleteTextView.isPopupShowing());
}
- public void testPerformFiltering() throws Throwable {
+ public void testPerformFiltering() {
if (isTvMode()) {
return;
}
- runTestOnUiThread(new Runnable() {
- public void run() {
+ mInstrumentation.runOnMainSync(() -> {
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.setValidator(mValidator);
@@ -452,7 +514,6 @@
mAutoCompleteTextView.setFocusable(true);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
- }
});
mInstrumentation.waitForIdleSync();
assertTrue(mAutoCompleteTextView.isPopupShowing());
@@ -461,11 +522,9 @@
// KeyBack will close the popup.
assertFalse(mAutoCompleteTextView.isPopupShowing());
- runTestOnUiThread(new Runnable() {
- public void run() {
+ mInstrumentation.runOnMainSync(() -> {
mAutoCompleteTextView.dismissDropDown();
mAutoCompleteTextView.setText(STRING_TEST);
- }
});
mInstrumentation.waitForIdleSync();
@@ -478,12 +537,10 @@
android.R.layout.simple_dropdown_item_1line, WORDS);
// Set Threshold to 4 charactersonKeyDown
- runTestOnUiThread(new Runnable() {
- public void run() {
+ mInstrumentation.runOnMainSync(() -> {
mAutoCompleteTextView.setAdapter(adapter);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.setText("");
- }
});
mInstrumentation.waitForIdleSync();
// Create and get the filter.
@@ -495,38 +552,27 @@
if (mNumeric) {
// "numeric" in case of 12-key(NUMERIC) keyboard
mInstrumentation.sendStringSync("6688633777444222");
- new PollingCheck() {
- @Override
- protected boolean check() {
- return "numeric".equals(filter.getResult());
- }
- }.run();
+ PollingCheck.waitFor(() -> "numeric".equals(filter.getResult()));
} else {
- Thread.sleep(200);
+ SystemClock.sleep(200);
mInstrumentation.sendStringSync(STRING_TEST);
- new PollingCheck() {
- @Override
- protected boolean check() {
- return STRING_TEST.equals(filter.getResult());
- }
- }.run();
+ PollingCheck.waitFor(() -> STRING_TEST.equals(filter.getResult()));
}
}
- public void testPerformCompletion() throws Throwable {
+ public void testPerformCompletionWithDPad() {
if (isTvMode()) {
return;
}
- final MockOnItemClickListener listener = new MockOnItemClickListener();
+ final AdapterView.OnItemClickListener mockItemClickListener =
+ mock(AdapterView.OnItemClickListener.class);
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
- runTestOnUiThread(new Runnable() {
- public void run() {
- mAutoCompleteTextView.setOnItemClickListener(listener);
- mAutoCompleteTextView.setAdapter(mAdapter);
- mAutoCompleteTextView.requestFocus();
- mAutoCompleteTextView.showDropDown();
- }
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+ mAutoCompleteTextView.setAdapter(mAdapter);
+ mAutoCompleteTextView.requestFocus();
+ mAutoCompleteTextView.showDropDown();
});
mInstrumentation.waitForIdleSync();
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
@@ -535,54 +581,112 @@
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
mInstrumentation.waitForIdleSync();
- assertTrue(listener.isOnItemClicked());
-
+ verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
+ eq(0), eq(0L));
assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
- // re-set 'clicked' flag to false
- listener.clearItemClickedStatus();
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- mAutoCompleteTextView.showDropDown();
- }
- });
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.showDropDown());
mInstrumentation.waitForIdleSync();
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- assertTrue(listener.isOnItemClicked());
+ verify(mockItemClickListener, times(2)).onItemClick(any(AdapterView.class), any(View.class),
+ eq(0), eq(0L));
assertEquals(WORDS[0], mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
- listener.clearItemClickedStatus();
- runTestOnUiThread(new Runnable() {
- public void run() {
- mAutoCompleteTextView.showDropDown();
- }
- });
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.showDropDown());
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
// Test normal key code.
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_0);
- assertFalse(listener.isOnItemClicked());
+ verifyNoMoreInteractions(mockItemClickListener);
assertNotSame("", mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
- listener.clearItemClickedStatus();
-
// Test the method on the scene of popup is closed.
- runTestOnUiThread(new Runnable() {
- public void run() {
- mAutoCompleteTextView.dismissDropDown();
- }
- });
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.dismissDropDown());
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_ENTER);
- assertFalse(listener.isOnItemClicked());
+ verifyNoMoreInteractions(mockItemClickListener);
assertNotSame("", mAutoCompleteTextView.getText().toString());
assertFalse(mAutoCompleteTextView.isPerformingCompletion());
}
+ public void testPerformCompletionExplicit() {
+ final AdapterView.OnItemClickListener mockItemClickListener =
+ mock(AdapterView.OnItemClickListener.class);
+ assertFalse(mAutoCompleteTextView.isPerformingCompletion());
+
+ // Create a custom watcher that checks isPerformingCompletion to return true
+ // in the "middle" of the performCompletion processing. We also spy on this watcher
+ // to make sure that its onTextChanged is invoked.
+ final TextWatcher myTextWatcher = new MyTextWatcher(WORDS[1]);
+ final TextWatcher spyTextWatcher = spy(myTextWatcher);
+ mAutoCompleteTextView.addTextChangedListener(spyTextWatcher);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+ mAutoCompleteTextView.setAdapter(mAdapter);
+ mAutoCompleteTextView.requestFocus();
+ mAutoCompleteTextView.showDropDown();
+ });
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mAutoCompleteTextView.isPopupShowing());
+ assertFalse(mAutoCompleteTextView.isPerformingCompletion());
+
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.performCompletion());
+ verify(mockItemClickListener, times(1)).onItemClick(any(AdapterView.class), any(View.class),
+ eq(1), eq(1L));
+ assertEquals(WORDS[1], mAutoCompleteTextView.getText().toString());
+ assertFalse(mAutoCompleteTextView.isPerformingCompletion());
+ assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+ verify(spyTextWatcher, atLeastOnce()).onTextChanged(TestUtils.sameCharSequence(WORDS[1]),
+ eq(0), eq(0), eq(WORDS[1].length()));
+ verifyNoMoreInteractions(mockItemClickListener);
+ }
+
+ public void testSetTextWithCompletion() {
+ final AdapterView.OnItemClickListener mockItemClickListener =
+ mock(AdapterView.OnItemClickListener.class);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+ mAutoCompleteTextView.setAdapter(mAdapter);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("testO", true));
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mAutoCompleteTextView.isPopupShowing());
+ verifyZeroInteractions(mockItemClickListener);
+ }
+
+ public void testSetTextWithNoCompletion() {
+ final AdapterView.OnItemClickListener mockItemClickListener =
+ mock(AdapterView.OnItemClickListener.class);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
+ mAutoCompleteTextView.setAdapter(mAdapter);
+ });
+ mInstrumentation.waitForIdleSync();
+
+ assertFalse(mAutoCompleteTextView.isPopupShowing());
+
+ mInstrumentation.runOnMainSync(() -> mAutoCompleteTextView.setText("testO", false));
+ mInstrumentation.waitForIdleSync();
+
+ assertFalse(mAutoCompleteTextView.isPopupShowing());
+ verifyZeroInteractions(mockItemClickListener);
+ }
+
@UiThreadTest
public void testPerformValidation() {
final CharSequence text = "this";
@@ -596,41 +700,27 @@
mAutoCompleteTextView.setValidator(null);
}
- public void testSetCompletionHint() {
+ public void testAccessCompletionHint() {
mAutoCompleteTextView.setCompletionHint("TEST HINT");
+ assertEquals("TEST HINT", mAutoCompleteTextView.getCompletionHint());
+
+ mAutoCompleteTextView.setCompletionHint(null);
+ assertNull(mAutoCompleteTextView.getCompletionHint());
}
- public void testOnAttachedToWindow() {
- // implement details, do not test
- }
+ public void testAccessListSelection() {
+ final AdapterView.OnItemClickListener mockItemClickListener =
+ mock(AdapterView.OnItemClickListener.class);
- public void testOnCommitCompletion() {
- // implement details, do not test
- }
-
- public void testOnDetachedFromWindow() {
- // implement details, do not test
- }
-
- public void testOnKeyPreIme() {
- // implement details, do not test
- }
-
- public void testAccessListSelection() throws Throwable {
- final MockOnItemClickListener listener = new MockOnItemClickListener();
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- mAutoCompleteTextView.setOnItemClickListener(listener);
+ mInstrumentation.runOnMainSync(() -> {
+ mAutoCompleteTextView.setOnItemClickListener(mockItemClickListener);
mAutoCompleteTextView.setAdapter(mAdapter);
mAutoCompleteTextView.requestFocus();
mAutoCompleteTextView.showDropDown();
- }
});
mInstrumentation.waitForIdleSync();
- runTestOnUiThread(new Runnable() {
- public void run() {
+ mInstrumentation.runOnMainSync(() -> {
mAutoCompleteTextView.setListSelection(1);
assertEquals(1, mAutoCompleteTextView.getListSelection());
@@ -639,7 +729,6 @@
mAutoCompleteTextView.clearListSelection();
assertEquals(2, mAutoCompleteTextView.getListSelection());
- }
});
mInstrumentation.waitForIdleSync();
}
@@ -660,75 +749,25 @@
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, mAutoCompleteTextView.getDropDownWidth());
}
- private static class MockOnItemClickListener implements AdapterView.OnItemClickListener {
- private boolean mOnItemClickedFlag = false;
-
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mOnItemClickedFlag = true;
- return;
- }
-
- public boolean isOnItemClicked() {
- return mOnItemClickedFlag;
- }
-
- public void clearItemClickedStatus() {
- mOnItemClickedFlag = false;
- }
- }
-
- private static class MockOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- return;
- }
-
- public void onNothingSelected(AdapterView<?> parent) {
- return;
- }
- }
-
private class MockValidator implements AutoCompleteTextView.Validator {
public CharSequence fixText(CharSequence invalidText) {
return STRING_VALIDATED;
}
public boolean isValid(CharSequence text) {
- if (text == STRING_TEST) {
- return true;
- }
- return false;
+ return (text == STRING_TEST);
}
}
- private static class MockAutoCompleteTextView extends AutoCompleteTextView {
- private boolean mOnTextChangedFlag = false;
- private boolean mOnFilterCompleteFlag = false;
- private String lastChangeText = "";
- private int mStart = 0;
- private int mBefore = 0;
- private int mAfter = 0;
-
- public void resetStatus() {
- mOnTextChangedFlag = false;
- mOnFilterCompleteFlag = false;
- mStart = 0;
- mBefore = 0;
- mAfter = 0;
- }
-
+ protected static class MockAutoCompleteTextView extends AutoCompleteTextView {
public MockAutoCompleteTextView(Context context) {
super(context);
- resetStatus();
}
public MockAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
- protected MockAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
@Override
protected CharSequence convertSelectionToString(Object selectedItem) {
return super.convertSelectionToString(selectedItem);
@@ -745,16 +784,6 @@
}
@Override
- protected void onTextChanged(CharSequence text, int start, int before, int after) {
- super.onTextChanged(text, start, before, after);
- mOnTextChangedFlag = true;
- lastChangeText = text.toString();
- mStart = start;
- mBefore = before;
- mAfter = after;
- }
-
- @Override
protected void performFiltering(CharSequence text, int keyCode) {
super.performFiltering(text, keyCode);
}
@@ -768,36 +797,6 @@
protected boolean setFrame(int l, int t, int r, int b) {
return super.setFrame(l, t, r, b);
}
-
- @Override
- public void onFilterComplete(int count) {
- super.onFilterComplete(count);
- mOnFilterCompleteFlag = true;
- }
-
- protected boolean isOnTextChanged() {
- return mOnTextChangedFlag;
- }
-
- protected String getLastChangeText() {
- return lastChangeText;
- }
-
- protected boolean isOnFilterComplete() {
- return mOnFilterCompleteFlag;
- }
-
- protected int getStart() {
- return mStart;
- }
-
- protected int getBefore() {
- return mBefore;
- }
-
- protected int getAfter() {
- return mAfter;
- }
}
private static class MockFilter extends Filter {
diff --git a/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
index 31ad341..283a515 100644
--- a/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
@@ -18,14 +18,22 @@
import android.annotation.ColorInt;
import android.app.Instrumentation;
+import android.graphics.Rect;
+import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
import android.widget.CalendarView;
+import android.widget.ScrollView;
import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.ViewTestUtils;
import java.util.Calendar;
import java.util.GregorianCalendar;
+import static org.mockito.Mockito.*;
+
@MediumTest
public class CalendarViewTest extends ActivityInstrumentationTestCase2<CalendarViewCtsActivity> {
private CalendarViewCtsActivity mActivity;
@@ -103,6 +111,64 @@
assertEquals(mCalendarViewMaterial.getMaxDate(), maxDate);
}
+ private void verifyOnDateChangeListener(CalendarView calendarView,
+ boolean onlyAllowOneChangeEvent) {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ final CalendarView.OnDateChangeListener mockDateChangeListener =
+ mock(CalendarView.OnDateChangeListener.class);
+ calendarView.setOnDateChangeListener(mockDateChangeListener);
+
+ // Go back to September 2008
+ final Calendar calendar = new GregorianCalendar();
+ calendar.set(Calendar.YEAR, 2008);
+ calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
+ calendar.set(Calendar.DAY_OF_MONTH, 16);
+ instrumentation.runOnMainSync(
+ () -> calendarView.setDate(calendar.getTime().getTime(), false, true));
+ instrumentation.waitForIdleSync();
+
+ // Get bounds of 09/23/2008
+ calendar.set(Calendar.DAY_OF_MONTH, 23);
+ final Rect dayBounds = new Rect();
+ final boolean getDayBoundsSuccess = calendarView.getBoundsForDate(
+ calendar.getTime().getTime(), dayBounds);
+ assertTrue(getDayBoundsSuccess);
+
+ if (onlyAllowOneChangeEvent) {
+ verifyZeroInteractions(mockDateChangeListener);
+ }
+
+ // Use instrumentation to emulate a tap on 09/23/2008
+ ViewTestUtils.emulateTapOnScreen(instrumentation, calendarView,
+ dayBounds.left + dayBounds.width() / 2,
+ dayBounds.top + dayBounds.height() / 2);
+
+ verify(mockDateChangeListener, times(1)).onSelectedDayChange(calendarView,
+ 2008, Calendar.SEPTEMBER, 23);
+ if (onlyAllowOneChangeEvent) {
+ verifyNoMoreInteractions(mockDateChangeListener);
+ }
+ }
+
+ public void testOnDateChangeListenerHolo() {
+ // Scroll the Holo calendar view all the way up so it's fully visible
+ final ScrollView scroller = (ScrollView) mActivity.findViewById(R.id.scroller);
+ final ViewGroup container = (ViewGroup) scroller.findViewById(R.id.container);
+ final Instrumentation instrumentation = getInstrumentation();
+
+ instrumentation.runOnMainSync(() -> scroller.scrollTo(0, container.getHeight()));
+ // Note that in pre-Material world we are "allowing" the CalendarView to notify
+ // the date change listener on multiple occasions. This is the old behavior of the widget.
+ verifyOnDateChangeListener(mCalendarViewHolo, false);
+ }
+
+ public void testOnDateChangeListenerMaterial() {
+ // Note that in Material world only "real" date change events are allowed to be reported
+ // to our listener. This is the new behavior of the widget.
+ verifyOnDateChangeListener(mCalendarViewMaterial, true);
+ }
+
public void testAppearanceMaterial() {
// The logic in this method is performed on a Material-styled CalendarView and
// non-deprecated attributes / visual appearance APIs
@@ -118,12 +184,12 @@
// Change the visual appearance of the widget
instrumentation.runOnMainSync(() -> {
- mCalendarViewMaterial.setFirstDayOfWeek(3);
+ mCalendarViewMaterial.setFirstDayOfWeek(Calendar.TUESDAY);
mCalendarViewMaterial.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
mCalendarViewMaterial.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
});
- assertEquals(3, mCalendarViewMaterial.getFirstDayOfWeek());
+ assertEquals(Calendar.TUESDAY, mCalendarViewMaterial.getFirstDayOfWeek());
assertEquals(R.style.TextAppearance_WithColorBlue,
mCalendarViewMaterial.getDateTextAppearance());
assertEquals(R.style.TextAppearance_WithColorMagenta,
@@ -166,7 +232,7 @@
mActivity.getColor(R.color.calendarview_week_separatorline_new);
instrumentation.runOnMainSync(() -> {
- mCalendarViewHolo.setFirstDayOfWeek(1);
+ mCalendarViewHolo.setFirstDayOfWeek(Calendar.SUNDAY);
mCalendarViewHolo.setShownWeekCount(4);
mCalendarViewHolo.setShowWeekNumber(true);
mCalendarViewHolo.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
@@ -178,7 +244,7 @@
mCalendarViewHolo.setWeekSeparatorLineColor(newWeekSeparatorLineColor);
});
- assertEquals(1, mCalendarViewHolo.getFirstDayOfWeek());
+ assertEquals(Calendar.SUNDAY, mCalendarViewHolo.getFirstDayOfWeek());
assertEquals(4, mCalendarViewHolo.getShownWeekCount());
assertTrue(mCalendarViewHolo.getShowWeekNumber());
assertEquals(R.style.TextAppearance_WithColorBlue,
diff --git a/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
new file mode 100644
index 0000000..9ad0b23
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.CheckBox;
+
+/**
+ * A minimal application for {@link CheckBox} test.
+ */
+public class CheckBoxCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.checkbox_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
index b3a6e67..083ae96 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckBoxTest.java
@@ -16,24 +16,41 @@
package android.widget.cts;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.Xml;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
import android.widget.CheckBox;
+import android.widget.cts.util.ViewTestUtils;
-public class CheckBoxTest extends AndroidTestCase {
+import static org.mockito.Mockito.*;
+
+@SmallTest
+public class CheckBoxTest extends ActivityInstrumentationTestCase2<CheckBoxCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private CheckBox mCheckBox;
+
+ public CheckBoxTest() {
+ super("android.widget.cts", CheckBoxCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mCheckBox = (CheckBox) mActivity.findViewById(R.id.check_box);
+ }
+
public void testConstructor() {
- XmlPullParser parser = mContext.getResources().getXml(R.layout.checkbox_layout);
- AttributeSet mAttrSet = Xml.asAttributeSet(parser);
-
- new CheckBox(mContext, mAttrSet, 0);
- new CheckBox(mContext, mAttrSet);
- new CheckBox(mContext);
+ new CheckBox(mActivity);
+ new CheckBox(mActivity, null);
+ new CheckBox(mActivity, null, android.R.attr.checkboxStyle);
+ new CheckBox(mActivity, null, 0,
+ android.R.style.Widget_Material_Light_CompoundButton_CheckBox);
try {
new CheckBox(null, null, -1);
@@ -56,4 +73,109 @@
// expected, test success.
}
}
+
+ public void testText() {
+ assertTrue(TextUtils.equals(
+ mActivity.getString(R.string.hello_world), mCheckBox.getText()));
+
+ mInstrumentation.runOnMainSync(() -> mCheckBox.setText("new text"));
+ assertTrue(TextUtils.equals("new text", mCheckBox.getText()));
+
+ mInstrumentation.runOnMainSync(() -> mCheckBox.setText(R.string.text_name));
+ assertTrue(TextUtils.equals(mActivity.getString(R.string.text_name), mCheckBox.getText()));
+ }
+
+ public void testAccessChecked() {
+ final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(CheckBox.OnCheckedChangeListener.class);
+ mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mCheckBox.isChecked());
+
+ // not checked -> not checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(false));
+ verifyZeroInteractions(mockCheckedChangeListener);
+ assertFalse(mCheckBox.isChecked());
+
+ // not checked -> checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(true));
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+ assertTrue(mCheckBox.isChecked());
+
+ // checked -> checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(true));
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+ assertTrue(mCheckBox.isChecked());
+
+ // checked -> not checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.setChecked(false));
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+ assertFalse(mCheckBox.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
+
+ public void testToggleViaApi() {
+ final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(CheckBox.OnCheckedChangeListener.class);
+ mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mCheckBox.isChecked());
+
+ // toggle to checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.toggle());
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+ assertTrue(mCheckBox.isChecked());
+
+ // toggle to not checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.toggle());
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+ assertFalse(mCheckBox.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
+
+ public void testToggleViaEmulatedTap() {
+ final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(CheckBox.OnCheckedChangeListener.class);
+ mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mCheckBox.isChecked());
+
+ // tap to checked
+ ViewTestUtils.emulateTapOnViewCenter(mInstrumentation, mCheckBox);
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+ assertTrue(mCheckBox.isChecked());
+
+ // tap to not checked
+ ViewTestUtils.emulateTapOnViewCenter(mInstrumentation, mCheckBox);
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+ assertFalse(mCheckBox.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
+
+ public void testToggleViaPerformClick() {
+ final CheckBox.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(CheckBox.OnCheckedChangeListener.class);
+ mCheckBox.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mCheckBox.isChecked());
+
+ // click to checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.performClick());
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, true);
+ assertTrue(mCheckBox.isChecked());
+
+ // click to not checked
+ mInstrumentation.runOnMainSync(() -> mCheckBox.performClick());
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mCheckBox, false);
+ assertFalse(mCheckBox.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
index 52bef54..066697a 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewCtsActivity.java
@@ -16,13 +16,12 @@
package android.widget.cts;
-import android.widget.cts.R;
-
import android.app.Activity;
import android.os.Bundle;
+import android.widget.CheckedTextView;
/**
- * A minimal application for CheckedTextView test.
+ * A minimal application for {@link CheckedTextView} test.
*/
public class CheckedTextViewCtsActivity extends Activity {
/**
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
index 039ca70..0240d61 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
@@ -16,17 +16,17 @@
package android.widget.cts;
-import android.os.Parcelable;
-import android.widget.cts.R;
-
-
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
-import android.content.res.Resources;
+import android.content.res.ColorStateList;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.AttributeSet;
import android.util.StateSet;
import android.view.View;
@@ -35,14 +35,19 @@
import android.widget.CheckedTextView;
import android.widget.ListAdapter;
import android.widget.ListView;
+import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.ViewTestUtils;
import java.util.Arrays;
+@SmallTest
public class CheckedTextViewTest extends
ActivityInstrumentationTestCase2<CheckedTextViewCtsActivity> {
- private Resources mResources;
- private Activity mActivity;
private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private ListView mListView;
+ private CheckedTextView mCheckedTextView;
+ private Parcelable mState;
public CheckedTextViewTest() {
super("android.widget.cts", CheckedTextViewCtsActivity.class);
@@ -51,32 +56,36 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mActivity = getActivity();
+
mInstrumentation = getInstrumentation();
- mResources = mActivity.getResources();
+ mActivity = getActivity();
+ mListView = (ListView) mActivity.findViewById(R.id.checkedtextview_listview);
+ mCheckedTextView = (CheckedTextView) mActivity.findViewById(R.id.checkedtextview_test);
}
public void testConstructor() {
- new MockCheckedTextView(mActivity, null, 0);
- new MockCheckedTextView(mActivity, null);
- new MockCheckedTextView(mActivity);
+ new CheckedTextView(mActivity);
+ new CheckedTextView(mActivity, null);
+ new CheckedTextView(mActivity, null, android.R.attr.checkedTextViewStyle);
+ new CheckedTextView(mActivity, null, 0,
+ android.R.style.Widget_Material_Light_CheckedTextView);
try {
- new MockCheckedTextView(null, null, -1);
+ new CheckedTextView(null, null, -1);
fail("Should throw NullPointerException.");
} catch (NullPointerException e) {
// expected, test success.
}
try {
- new MockCheckedTextView(null, null);
+ new CheckedTextView(null, null);
fail("Should throw NullPointerException.");
} catch (NullPointerException e) {
// expected, test success.
}
try {
- new MockCheckedTextView(null);
+ new CheckedTextView(null);
fail("Should throw NullPointerException.");
} catch (NullPointerException e) {
// expected, test success.
@@ -84,35 +93,29 @@
}
public void testChecked() {
- final ListView lv = (ListView) mActivity.findViewById(R.id.checkedtextview_listview);
+ mInstrumentation.runOnMainSync(() -> {
+ mListView.setAdapter(new CheckedTextViewAdapter());
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- lv.setAdapter(new CheckedTextViewAdapter());
-
- lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- lv.setItemChecked(1, true);
- }
+ mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ mListView.setItemChecked(1, true);
});
mInstrumentation.waitForIdleSync();
- assertEquals(1, lv.getCheckedItemPosition());
- assertTrue(lv.isItemChecked(1));
- assertFalse(lv.isItemChecked(0));
+ assertEquals(1, mListView.getCheckedItemPosition());
+ assertTrue(mListView.isItemChecked(1));
+ assertFalse(mListView.isItemChecked(0));
- ListAdapter adapter = lv.getAdapter();
- CheckedTextView view0 = (CheckedTextView) adapter.getView(0, null, null);
- CheckedTextView view1 = (CheckedTextView) adapter.getView(1, null, null);
- CheckedTextView view2 = (CheckedTextView) adapter.getView(2, null, null);
+ final ListAdapter adapter = mListView.getAdapter();
+ final CheckedTextView view0 = (CheckedTextView) adapter.getView(0, null, null);
+ final CheckedTextView view1 = (CheckedTextView) adapter.getView(1, null, null);
+ final CheckedTextView view2 = (CheckedTextView) adapter.getView(2, null, null);
assertFalse(view0.isChecked());
assertTrue(view1.isChecked());
assertFalse(view2.isChecked());
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
- lv.setItemChecked(2, true);
- }
+ mInstrumentation.runOnMainSync(() -> {
+ mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ mListView.setItemChecked(2, true);
});
mInstrumentation.waitForIdleSync();
assertFalse(view0.isChecked());
@@ -128,184 +131,219 @@
}
public void testToggle() {
- CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
- assertFalse(checkedTextView.isChecked());
+ assertFalse(mCheckedTextView.isChecked());
- checkedTextView.toggle();
- assertTrue(checkedTextView.isChecked());
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.toggle());
+ assertTrue(mCheckedTextView.isChecked());
- checkedTextView.toggle();
- assertFalse(checkedTextView.isChecked());
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.toggle());
+ assertFalse(mCheckedTextView.isChecked());
- checkedTextView.setChecked(true);
- checkedTextView.toggle();
- assertFalse(checkedTextView.isChecked());
+ mInstrumentation.runOnMainSync(() -> {
+ mCheckedTextView.setChecked(true);
+ mCheckedTextView.toggle();
+ });
+ assertFalse(mCheckedTextView.isChecked());
}
public void testDrawableStateChanged() {
MockCheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
- checkedTextView.reset();
assertFalse(checkedTextView.hasDrawableStateChanged());
checkedTextView.refreshDrawableState();
assertTrue(checkedTextView.hasDrawableStateChanged());
}
public void testSetPadding() {
- final CheckedTextView lv
- = (CheckedTextView) mActivity.findViewById(R.id.checkedtextview_test);
- assertNotNull(lv);
-
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- lv.setPadding(1, 2, 3, 4);
- lv.requestLayout();
- }
+ mInstrumentation.runOnMainSync(() -> {
+ mListView.setPadding(1, 2, 3, 4);
+ mListView.requestLayout();
});
mInstrumentation.waitForIdleSync();
- int origTop = lv.getPaddingTop();
- int origBottom = lv.getPaddingBottom();
- int origLeft = lv.getPaddingLeft();
- int origRight = lv.getPaddingRight();
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- lv.setPadding(10, 20, 30, 40);
- lv.requestLayout();
- }
+ final int origTop = mListView.getPaddingTop();
+ final int origBottom = mListView.getPaddingBottom();
+ final int origLeft = mListView.getPaddingLeft();
+ final int origRight = mListView.getPaddingRight();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mListView.setPadding(10, 20, 30, 40);
+ mListView.requestLayout();
});
mInstrumentation.waitForIdleSync();
- assertTrue(origTop < lv.getPaddingTop());
- assertTrue(origBottom < lv.getPaddingBottom());
- assertTrue(origLeft < lv.getPaddingLeft());
- assertTrue(origRight < lv.getPaddingRight());
+
+ assertTrue(origTop < mListView.getPaddingTop());
+ assertTrue(origBottom < mListView.getPaddingBottom());
+ assertTrue(origLeft < mListView.getPaddingLeft());
+ assertTrue(origRight < mListView.getPaddingRight());
}
private void cleanUpForceLayoutFlags(View view) {
if (view != null) {
- view.layout(0, 0, 0, 0);
+ mInstrumentation.runOnMainSync(() -> view.layout(0, 0, 0, 0));
assertFalse(view.isLayoutRequested());
}
}
public void testSetCheckMarkDrawableByDrawable() {
- CheckedTextView checkedTextView;
int basePaddingRight = 10;
// set drawable when checkedTextView is GONE
- checkedTextView = new MockCheckedTextView(mActivity);
- checkedTextView.setVisibility(View.GONE);
- Drawable firstDrawable = mResources.getDrawable(R.drawable.scenery);
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setVisibility(View.GONE));
+ final Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery);
firstDrawable.setVisible(true, false);
assertEquals(StateSet.WILD_CARD, firstDrawable.getState());
- cleanUpForceLayoutFlags(checkedTextView);
+ cleanUpForceLayoutFlags(mCheckedTextView);
- checkedTextView.setCheckMarkDrawable(firstDrawable);
- assertEquals(firstDrawable.getIntrinsicWidth(), checkedTextView.getPaddingRight());
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(firstDrawable));
+ assertEquals(firstDrawable.getIntrinsicWidth(), mCheckedTextView.getPaddingRight());
assertFalse(firstDrawable.isVisible());
- assertTrue(Arrays.equals(checkedTextView.getDrawableState(), firstDrawable.getState()));
- assertTrue(checkedTextView.isLayoutRequested());
+ assertTrue(Arrays.equals(mCheckedTextView.getDrawableState(), firstDrawable.getState()));
+ assertTrue(mCheckedTextView.isLayoutRequested());
+
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(null));
// update drawable when checkedTextView is VISIBLE
- checkedTextView = new MockCheckedTextView(mActivity);
- checkedTextView.setVisibility(View.VISIBLE);
- checkedTextView.setPadding(0, 0, basePaddingRight, 0);
- Drawable secondDrawable = mResources.getDrawable(R.drawable.pass);
+ mInstrumentation.runOnMainSync(() -> {
+ mCheckedTextView.setVisibility(View.VISIBLE);
+ mCheckedTextView.setPadding(0, 0, basePaddingRight, 0);
+ });
+ final Drawable secondDrawable = mActivity.getDrawable(R.drawable.pass);
secondDrawable.setVisible(true, false);
assertEquals(StateSet.WILD_CARD, secondDrawable.getState());
- cleanUpForceLayoutFlags(checkedTextView);
+ cleanUpForceLayoutFlags(mCheckedTextView);
- checkedTextView.setCheckMarkDrawable(secondDrawable);
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(secondDrawable));
assertEquals(secondDrawable.getIntrinsicWidth() + basePaddingRight,
- checkedTextView.getPaddingRight());
+ mCheckedTextView.getPaddingRight());
assertTrue(secondDrawable.isVisible());
- assertTrue(Arrays.equals(checkedTextView.getDrawableState(), secondDrawable.getState()));
- assertTrue(checkedTextView.isLayoutRequested());
+ assertTrue(Arrays.equals(mCheckedTextView.getDrawableState(), secondDrawable.getState()));
+ assertTrue(mCheckedTextView.isLayoutRequested());
- cleanUpForceLayoutFlags(checkedTextView);
- checkedTextView.setCheckMarkDrawable(null);
- assertEquals(basePaddingRight, checkedTextView.getPaddingRight());
- assertTrue(checkedTextView.isLayoutRequested());
+ cleanUpForceLayoutFlags(mCheckedTextView);
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(null));
+ assertEquals(basePaddingRight, mCheckedTextView.getPaddingRight());
+ assertTrue(mCheckedTextView.isLayoutRequested());
}
public void testSetCheckMarkDrawableById() {
- CheckedTextView checkedTextView;
int basePaddingRight = 10;
// set drawable
- checkedTextView = new MockCheckedTextView(mActivity);
- checkedTextView.setPadding(0, 0, basePaddingRight, 0);
- Drawable firstDrawable = mResources.getDrawable(R.drawable.scenery);
- cleanUpForceLayoutFlags(checkedTextView);
+ mInstrumentation.runOnMainSync(
+ () -> mCheckedTextView.setPadding(0, 0, basePaddingRight, 0));
+ Drawable firstDrawable = mActivity.getDrawable(R.drawable.scenery);
+ cleanUpForceLayoutFlags(mCheckedTextView);
- checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+ mInstrumentation.runOnMainSync(
+ () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery));
assertEquals(firstDrawable.getIntrinsicWidth() + basePaddingRight,
- checkedTextView.getPaddingRight());
- assertTrue(checkedTextView.isLayoutRequested());
+ mCheckedTextView.getPaddingRight());
+ assertTrue(mCheckedTextView.isLayoutRequested());
// set the same drawable again
- cleanUpForceLayoutFlags(checkedTextView);
- checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
+ cleanUpForceLayoutFlags(mCheckedTextView);
+ mInstrumentation.runOnMainSync(
+ () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery));
assertEquals(firstDrawable.getIntrinsicWidth() + basePaddingRight,
- checkedTextView.getPaddingRight());
- assertFalse(checkedTextView.isLayoutRequested());
+ mCheckedTextView.getPaddingRight());
+ assertFalse(mCheckedTextView.isLayoutRequested());
// update drawable
- Drawable secondDrawable = mResources.getDrawable(R.drawable.pass);
- checkedTextView.setCheckMarkDrawable(secondDrawable);
+ final Drawable secondDrawable = mActivity.getDrawable(R.drawable.pass);
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(secondDrawable));
assertEquals(secondDrawable.getIntrinsicWidth() + basePaddingRight,
- checkedTextView.getPaddingRight());
- assertTrue(checkedTextView.isLayoutRequested());
+ mCheckedTextView.getPaddingRight());
+ assertTrue(mCheckedTextView.isLayoutRequested());
+
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(null));
// resId is 0
- checkedTextView = new MockCheckedTextView(mActivity);
- checkedTextView.setPadding(0, 0, basePaddingRight, 0);
- cleanUpForceLayoutFlags(checkedTextView);
+ mInstrumentation.runOnMainSync(
+ () -> mCheckedTextView.setPadding(0, 0, basePaddingRight, 0));
+ cleanUpForceLayoutFlags(mCheckedTextView);
- checkedTextView.setCheckMarkDrawable(0);
- assertEquals(basePaddingRight, checkedTextView.getPaddingRight());
- assertFalse(checkedTextView.isLayoutRequested());
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setCheckMarkDrawable(0));
+ assertEquals(basePaddingRight, mCheckedTextView.getPaddingRight());
+ assertFalse(mCheckedTextView.isLayoutRequested());
}
public void testSetCheckMarkByMixedTypes() {
- CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
- cleanUpForceLayoutFlags(checkedTextView);
+ cleanUpForceLayoutFlags(mCheckedTextView);
// Specifically test for b/22626247 (AOSP issue 180455).
- checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
- checkedTextView.setCheckMarkDrawable(null);
- checkedTextView.setCheckMarkDrawable(R.drawable.scenery);
- assertNotNull(checkedTextView.getCheckMarkDrawable());
+ mInstrumentation.runOnMainSync(() -> {
+ mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery);
+ mCheckedTextView.setCheckMarkDrawable(null);
+ mCheckedTextView.setCheckMarkDrawable(R.drawable.scenery);
+ });
+ assertNotNull(mCheckedTextView.getCheckMarkDrawable());
}
public void testAccessInstanceState() {
- CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
- Parcelable state;
+ assertFalse(mCheckedTextView.isChecked());
+ assertFalse(mCheckedTextView.getFreezesText());
- assertFalse(checkedTextView.isChecked());
- assertFalse(checkedTextView.getFreezesText());
+ mInstrumentation.runOnMainSync(() -> mState = mCheckedTextView.onSaveInstanceState());
+ assertNotNull(mState);
+ assertFalse(mCheckedTextView.getFreezesText());
- state = checkedTextView.onSaveInstanceState();
- assertNotNull(state);
- assertFalse(checkedTextView.getFreezesText());
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setChecked(true));
- checkedTextView.setChecked(true);
-
- checkedTextView.onRestoreInstanceState(state);
- assertFalse(checkedTextView.isChecked());
- assertTrue(checkedTextView.isLayoutRequested());
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.onRestoreInstanceState(mState));
+ assertFalse(mCheckedTextView.isChecked());
+ assertTrue(mCheckedTextView.isLayoutRequested());
}
- public void testOnDraw() {
- // Do not test. Implementation details.
- }
+ public void testCheckMarkTinting() {
+ mInstrumentation.runOnMainSync(() -> mCheckedTextView.setChecked(true));
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView,
+ () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.icon_red));
- public void testOnCreateDrawableState() {
- // Do not test. Implementation details.
+ Drawable checkMark = mCheckedTextView.getCheckMarkDrawable();
+ TestUtils.assertAllPixelsOfColor("Initial state is red", checkMark,
+ checkMark.getBounds().width(), checkMark.getBounds().height(), false,
+ Color.RED, 1, true);
+
+ // With SRC_IN we're expecting the translucent tint color to "take over" the
+ // original red checkmark.
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView, () -> {
+ mCheckedTextView.setCheckMarkTintMode(PorterDuff.Mode.SRC_IN);
+ mCheckedTextView.setCheckMarkTintList(ColorStateList.valueOf(0x8000FF00));
+ });
+
+ assertEquals(PorterDuff.Mode.SRC_IN, mCheckedTextView.getCheckMarkTintMode());
+ assertEquals(0x8000FF00, mCheckedTextView.getCheckMarkTintList().getDefaultColor());
+ checkMark = mCheckedTextView.getCheckMarkDrawable();
+ TestUtils.assertAllPixelsOfColor("Expected 50% green", checkMark,
+ checkMark.getIntrinsicWidth(), checkMark.getIntrinsicHeight(), false,
+ 0x8000FF00, 1, true);
+
+ // With SRC_OVER we're expecting the translucent tint color to be drawn on top
+ // of the original red checkmark, creating a composite color fill as the result.
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView,
+ () -> mCheckedTextView.setCheckMarkTintMode(PorterDuff.Mode.SRC_OVER));
+
+ assertEquals(PorterDuff.Mode.SRC_OVER, mCheckedTextView.getCheckMarkTintMode());
+ assertEquals(0x8000FF00, mCheckedTextView.getCheckMarkTintList().getDefaultColor());
+ checkMark = mCheckedTextView.getCheckMarkDrawable();
+ TestUtils.assertAllPixelsOfColor("Expected 50% green over full red", checkMark,
+ checkMark.getIntrinsicWidth(), checkMark.getIntrinsicHeight(), false,
+ TestUtils.compositeColors(0x8000FF00, Color.RED), 1, true);
+
+ // Switch to a different color for the underlying checkmark and verify that the
+ // currently configured tinting (50% green overlay) is still respected
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mCheckedTextView,
+ () -> mCheckedTextView.setCheckMarkDrawable(R.drawable.icon_yellow));
+ assertEquals(PorterDuff.Mode.SRC_OVER, mCheckedTextView.getCheckMarkTintMode());
+ assertEquals(0x8000FF00, mCheckedTextView.getCheckMarkTintList().getDefaultColor());
+ checkMark = mCheckedTextView.getCheckMarkDrawable();
+ TestUtils.assertAllPixelsOfColor("Expected 50% green over full yellow", checkMark,
+ checkMark.getIntrinsicWidth(), checkMark.getIntrinsicHeight(), false,
+ TestUtils.compositeColors(0x8000FF00, Color.YELLOW), 1, true);
}
private static final class MockCheckedTextView extends CheckedTextView {
- private boolean mHasRefreshDrawableState = false;
private boolean mHasDrawableStateChanged = false;
public MockCheckedTextView(Context context) {
@@ -320,10 +358,6 @@
super(context, attrs, defStyle);
}
- public static int[] getSuperViewStateSet() {
- return ENABLED_STATE_SET;
- }
-
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
@@ -340,24 +374,9 @@
super.onDraw(canvas);
}
- @Override
- public void refreshDrawableState() {
- mHasRefreshDrawableState = true;
- super.refreshDrawableState();
- }
-
- public boolean hasRefreshDrawableState() {
- return mHasRefreshDrawableState;
- }
-
public boolean hasDrawableStateChanged() {
return mHasDrawableStateChanged;
}
-
- public void reset() {
- mHasRefreshDrawableState = false;
- mHasDrawableStateChanged = false;
- }
}
private class CheckedTextViewAdapter extends BaseAdapter {
diff --git a/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
new file mode 100644
index 0000000..81e6e69
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.DatePicker;
+
+/**
+ * A minimal application for {@link DatePicker} test.
+ */
+public class DatePickerCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.datepicker_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
index c48f684..f2d4c88 100644
--- a/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerTest.java
@@ -16,120 +16,223 @@
package android.widget.cts;
-import android.widget.cts.R;
-
+import android.app.Activity;
+import android.app.Instrumentation;
import android.content.Context;
-import android.content.res.XmlResourceParser;
import android.os.Parcelable;
-import android.test.InstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
-import android.util.AttributeSet;
+import android.test.suitebuilder.annotation.MediumTest;
import android.util.SparseArray;
-import android.util.Xml;
import android.view.View;
import android.widget.DatePicker;
-import android.widget.cts.util.XmlUtils;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import static org.mockito.Mockito.*;
/**
* Test {@link DatePicker}.
*/
-public class DatePickerTest extends InstrumentationTestCase {
+@MediumTest
+public class DatePickerTest extends ActivityInstrumentationTestCase2<DatePickerCtsActivity> {
+ private Activity mActivity;
+ private DatePicker mDatePickerSpinnerMode;
+ private DatePicker mDatePickerCalendarMode;
- private Context mContext;
+ public DatePickerTest() {
+ super("android.widget.cts", DatePickerCtsActivity.class);
+ }
@Override
- public void setUp() {
- mContext = getInstrumentation().getTargetContext();
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mDatePickerSpinnerMode = (DatePicker) mActivity.findViewById(R.id.date_picker_spinner_mode);
+ mDatePickerCalendarMode =
+ (DatePicker) mActivity.findViewById(R.id.date_picker_calendar_mode);
}
- @UiThreadTest
public void testConstructor() {
- new DatePicker(mContext);
+ new DatePicker(mActivity);
- new DatePicker(mContext, null);
+ new DatePicker(mActivity, null);
- new DatePicker(mContext, getAttributeSet(R.layout.datepicker_layout));
+ new DatePicker(mActivity, null, android.R.attr.datePickerStyle);
- new DatePicker(mContext, getAttributeSet(R.layout.datepicker_layout), 0);
-
- // Test constructor with null Context, in fact, previous two functions will finally invoke
- // this version.
- try {
- // Test with null Context
- new DatePicker(null, getAttributeSet(R.layout.datepicker_layout), 0);
- fail("should throw NullPointerException");
- } catch (Exception e) {
- }
+ new DatePicker(mActivity, null, 0, android.R.style.Widget_Material_Light_DatePicker);
}
- @UiThreadTest
public void testSetEnabled() {
- MockDatePicker datePicker = createDatePicker();
+ final Instrumentation instrumentation = getInstrumentation();
- assertTrue(datePicker.isEnabled());
+ assertTrue(mDatePickerCalendarMode.isEnabled());
- datePicker.setEnabled(false);
- assertFalse(datePicker.isEnabled());
+ instrumentation.runOnMainSync(() -> mDatePickerCalendarMode.setEnabled(false));
+ assertFalse(mDatePickerCalendarMode.isEnabled());
- datePicker.setEnabled(true);
- assertTrue(datePicker.isEnabled());
+ instrumentation.runOnMainSync(() -> mDatePickerCalendarMode.setEnabled(true));
+ assertTrue(mDatePickerCalendarMode.isEnabled());
}
- @UiThreadTest
+ private void verifyInit(DatePicker datePicker) {
+ final Instrumentation instrumentation = getInstrumentation();
+ final DatePicker.OnDateChangedListener mockDateChangeListener =
+ mock(DatePicker.OnDateChangedListener.class);
+
+ instrumentation.runOnMainSync(
+ () -> datePicker.init(2000, 10, 15, mockDateChangeListener));
+ assertEquals(2000, datePicker.getYear());
+ assertEquals(10, datePicker.getMonth());
+ assertEquals(15, datePicker.getDayOfMonth());
+
+ verifyZeroInteractions(mockDateChangeListener);
+ }
+
public void testInit() {
- MockOnDateChangedListener onDateChangedListener = new MockOnDateChangedListener();
- DatePicker datePicker = createDatePicker();
+ verifyInit(mDatePickerSpinnerMode);
+ verifyInit(mDatePickerCalendarMode);
+ }
- /* The month display uses 1-12 but our internal state stores it
- * 0-11 so add one when setting the display.
- */
- datePicker.init(2000, 10, 15, onDateChangedListener);
+ private void verifyAccessDate(DatePicker datePicker) {
+ final Instrumentation instrumentation = getInstrumentation();
+ final DatePicker.OnDateChangedListener mockDateChangeListener =
+ mock(DatePicker.OnDateChangedListener.class);
+
+ instrumentation.runOnMainSync(() -> datePicker.init(2000, 10, 15, mockDateChangeListener));
assertEquals(2000, datePicker.getYear());
assertEquals(10, datePicker.getMonth());
assertEquals(15, datePicker.getDayOfMonth());
+ verify(mockDateChangeListener, never()).onDateChanged(any(DatePicker.class), anyInt(),
+ anyInt(), anyInt());
+
+ instrumentation.runOnMainSync(() -> datePicker.updateDate(1989, 9, 19));
+ assertEquals(1989, datePicker.getYear());
+ assertEquals(9, datePicker.getMonth());
+ assertEquals(19, datePicker.getDayOfMonth());
+ verify(mockDateChangeListener, times(1)).onDateChanged(datePicker, 1989, 9, 19);
+
+ verifyNoMoreInteractions(mockDateChangeListener);
}
- @UiThreadTest
public void testAccessDate() {
- DatePicker datePicker = createDatePicker();
+ verifyAccessDate(mDatePickerSpinnerMode);
+ verifyAccessDate(mDatePickerCalendarMode);
+ }
- /* The month display uses 1-12 but our internal state stores it
- * 0-11 so add one when setting the display.
- */
- MockOnDateChangedListener onDateChangedListener = new MockOnDateChangedListener();
- datePicker.init(2000, 10, 15, onDateChangedListener);
- assertEquals(2000, datePicker.getYear());
- assertEquals(10, datePicker.getMonth());
- assertEquals(15, datePicker.getDayOfMonth());
+ private void verifyUpdateDate(DatePicker datePicker) {
+ final Instrumentation instrumentation = getInstrumentation();
- datePicker.updateDate(1989, 9, 19);
+ instrumentation.runOnMainSync(() -> datePicker.updateDate(1989, 9, 19));
assertEquals(1989, datePicker.getYear());
assertEquals(9, datePicker.getMonth());
assertEquals(19, datePicker.getDayOfMonth());
}
- @UiThreadTest
public void testUpdateDate() {
- DatePicker datePicker = createDatePicker();
+ verifyUpdateDate(mDatePickerSpinnerMode);
+ verifyUpdateDate(mDatePickerCalendarMode);
+ }
- // Test normal input values
- /* The month display uses 1-12 but our internal state stores it
- * 0-11 so add one when setting the display.
- */
- datePicker.updateDate(1989, 9, 19);
- assertEquals(1989, datePicker.getYear());
- assertEquals(9, datePicker.getMonth());
- assertEquals(19, datePicker.getDayOfMonth());
+ private void verifyMinMaxDate(DatePicker datePicker) {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // Use a range of minus/plus one year as min/max dates
+ final Calendar minCalendar = new GregorianCalendar();
+ minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
+ final Calendar maxCalendar = new GregorianCalendar();
+ maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
+
+ final long minDate = minCalendar.getTime().getTime();
+ final long maxDate = maxCalendar.getTime().getTime();
+
+ instrumentation.runOnMainSync(() -> {
+ datePicker.setMinDate(minDate);
+ datePicker.setMaxDate(maxDate);
+ });
+
+ assertEquals(datePicker.getMinDate(), minDate);
+ assertEquals(datePicker.getMaxDate(), maxDate);
+ }
+
+ public void testMinMaxDate() {
+ verifyMinMaxDate(mDatePickerSpinnerMode);
+ verifyMinMaxDate(mDatePickerCalendarMode);
+ }
+
+ private void verifyFirstDayOfWeek(DatePicker datePicker) {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ instrumentation.runOnMainSync(() -> datePicker.setFirstDayOfWeek(Calendar.TUESDAY));
+ assertEquals(Calendar.TUESDAY, datePicker.getFirstDayOfWeek());
+
+ instrumentation.runOnMainSync(() -> datePicker.setFirstDayOfWeek(Calendar.SUNDAY));
+ assertEquals(Calendar.SUNDAY, datePicker.getFirstDayOfWeek());
+ }
+
+ public void testFirstDayOfWeek() {
+ verifyFirstDayOfWeek(mDatePickerSpinnerMode);
+ verifyFirstDayOfWeek(mDatePickerCalendarMode);
+ }
+
+ public void testCalendarViewInSpinnerMode() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ assertNotNull(mDatePickerSpinnerMode.getCalendarView());
+
+ // Update the DatePicker and test that its CalendarView is synced to the same date
+ final Calendar calendar = new GregorianCalendar();
+ calendar.set(Calendar.YEAR, 2008);
+ calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
+ calendar.set(Calendar.DAY_OF_MONTH, 23);
+ instrumentation.runOnMainSync(
+ () -> mDatePickerSpinnerMode.updateDate(
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH)));
+
+ final Calendar calendarFromSpinner = new GregorianCalendar();
+ final long timeFromSpinnerCalendar = mDatePickerSpinnerMode.getCalendarView().getDate();
+ calendarFromSpinner.setTimeInMillis(timeFromSpinnerCalendar);
+
+ assertEquals(calendar.get(Calendar.YEAR), calendarFromSpinner.get(Calendar.YEAR));
+ assertEquals(calendar.get(Calendar.MONTH), calendarFromSpinner.get(Calendar.MONTH));
+ assertEquals(calendar.get(Calendar.DAY_OF_MONTH),
+ calendarFromSpinner.get(Calendar.DAY_OF_MONTH));
+ }
+
+ public void testPartsVisibilityInSpinnerMode() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+ assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+
+ instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setSpinnersShown(false));
+ assertFalse(mDatePickerSpinnerMode.getSpinnersShown());
+ assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
+
+ instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setCalendarViewShown(false));
+ assertFalse(mDatePickerSpinnerMode.getSpinnersShown());
+ assertFalse(mDatePickerSpinnerMode.getCalendarViewShown());
+
+ instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setSpinnersShown(true));
+ assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+ assertFalse(mDatePickerSpinnerMode.getCalendarViewShown());
+
+ instrumentation.runOnMainSync(() -> mDatePickerSpinnerMode.setCalendarViewShown(true));
+ assertTrue(mDatePickerSpinnerMode.getSpinnersShown());
+ assertTrue(mDatePickerSpinnerMode.getCalendarViewShown());
}
@UiThreadTest
- public void testOnSaveInstanceState() {
- MockDatePicker datePicker = createDatePicker();
+ public void testAccessInstanceState() {
+ MockDatePicker datePicker = new MockDatePicker(mActivity);
datePicker.updateDate(2008, 9, 10);
SparseArray<Parcelable> container = new SparseArray<Parcelable>();
- // Test onSaveHierarchyState
+ // Test saveHierarchyState -> onSaveInstanceState path
assertEquals(View.NO_ID, datePicker.getId());
datePicker.setId(99);
assertFalse(datePicker.hasCalledOnSaveInstanceState());
@@ -137,43 +240,23 @@
assertEquals(1, datePicker.getChildCount());
assertTrue(datePicker.hasCalledOnSaveInstanceState());
- // Test dispatchRestoreInstanceState
- datePicker = createDatePicker();
+ // Test dispatchRestoreInstanceState -> onRestoreInstanceState path
+ datePicker = new MockDatePicker(mActivity);
datePicker.setId(99);
assertFalse(datePicker.hasCalledOnRestoreInstanceState());
datePicker.dispatchRestoreInstanceState(container);
assertEquals(2008, datePicker.getYear());
assertEquals(9, datePicker.getMonth());
assertEquals(10, datePicker.getDayOfMonth());
-
- // Test onRestoreInstanceState
assertTrue(datePicker.hasCalledOnRestoreInstanceState());
}
- private AttributeSet getAttributeSet(int resourceId) {
- final XmlResourceParser parser = mContext.getResources().getXml(resourceId);
- try {
- XmlUtils.beginDocument(parser, "RelativeLayout");
- } catch (Exception e) {
- fail("Found unexpected loading process error before invoking generateLayoutParams.");
- }
- final AttributeSet attr = Xml.asAttributeSet(parser);
- assertNotNull(attr);
- return attr;
- }
-
- private MockDatePicker createDatePicker() {
- MockDatePicker datePicker = new MockDatePicker(mContext,
- getAttributeSet(R.layout.datepicker_layout));
- return datePicker;
- }
-
private class MockDatePicker extends DatePicker {
private boolean mCalledOnSaveInstanceState = false;
private boolean mCalledOnRestoreInstanceState = false;
- public MockDatePicker(Context context, AttributeSet attrs) {
- super(context, attrs);
+ public MockDatePicker(Context context) {
+ super(context);
}
@Override
@@ -201,10 +284,4 @@
return mCalledOnRestoreInstanceState;
}
}
-
- private class MockOnDateChangedListener implements DatePicker.OnDateChangedListener {
- public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
-
- }
- }
}
diff --git a/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
new file mode 100644
index 0000000..5f91950
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ImageButton;
+
+/**
+ * A minimal application for {@link ImageButton} test.
+ */
+public class ImageButtonCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.imagebutton_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
index 05c0e3f..f1eab1e 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageButtonTest.java
@@ -16,27 +16,39 @@
package android.widget.cts;
-import android.widget.cts.R;
-
-
-import org.xmlpull.v1.XmlPullParser;
-
-import android.test.AndroidTestCase;
-import android.util.AttributeSet;
-import android.util.Xml;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
import android.widget.ImageButton;
+import android.widget.cts.util.TestUtils;
-public class ImageButtonTest extends AndroidTestCase {
+@SmallTest
+public class ImageButtonTest extends ActivityInstrumentationTestCase2<ImageButtonCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private ImageButton mImageButton;
+
+ public ImageButtonTest() {
+ super("android.widget.cts", ImageButtonCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mImageButton = (ImageButton) mActivity.findViewById(R.id.image_button);
+ }
+
public void testConstructor() {
- XmlPullParser parser = getContext().getResources().getXml(R.layout.imagebutton_test);
- AttributeSet attrs = Xml.asAttributeSet(parser);
- assertNotNull(attrs);
-
- new ImageButton(getContext());
-
- new ImageButton(getContext(), attrs);
-
- new ImageButton(getContext(), attrs, 0);
+ new ImageButton(mActivity);
+ new ImageButton(mActivity, null);
+ new ImageButton(mActivity, null, android.R.attr.imageButtonStyle);
+ new ImageButton(mActivity, null, 0, android.R.style.Widget_Material_Light_ImageButton);
try {
new ImageButton(null);
@@ -57,7 +69,23 @@
}
}
- public void testOnSetAlpha() {
- // Do not test, it's controlled by View. Implementation details.
+ public void testImageSource() {
+ Drawable imageButtonDrawable = mImageButton.getDrawable();
+ TestUtils.assertAllPixelsOfColor("Default source is red", imageButtonDrawable,
+ imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+ true, Color.RED, 1, false);
+
+ mInstrumentation.runOnMainSync(() -> mImageButton.setImageResource(R.drawable.icon_green));
+ imageButtonDrawable = mImageButton.getDrawable();
+ TestUtils.assertAllPixelsOfColor("New source is green", imageButtonDrawable,
+ imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+ true, Color.GREEN, 1, false);
+
+ mInstrumentation.runOnMainSync(
+ () -> mImageButton.setImageDrawable(mActivity.getDrawable(R.drawable.icon_yellow)));
+ imageButtonDrawable = mImageButton.getDrawable();
+ TestUtils.assertAllPixelsOfColor("New source is yellow", imageButtonDrawable,
+ imageButtonDrawable.getIntrinsicWidth(), imageButtonDrawable.getIntrinsicHeight(),
+ true, Color.YELLOW, 1, false);
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 4d0903a..24878ce 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,15 +16,20 @@
package android.widget.cts;
-import org.xmlpull.v1.XmlPullParser;
-
+import android.annotation.ColorInt;
import android.app.Activity;
+import android.app.Instrumentation;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase;
import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.AttributeSet;
import android.util.Xml;
+import android.view.Gravity;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
@@ -34,7 +39,10 @@
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;
-import android.widget.cts.R;
+import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.ViewTestUtils;
+
+import org.xmlpull.v1.XmlPullParser;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -42,6 +50,7 @@
/**
* Test {@link LinearLayout}.
*/
+@SmallTest
public class LinearLayoutTest extends ActivityInstrumentationTestCase<LinearLayoutCtsActivity> {
private Context mContext;
private Activity mActivity;
@@ -152,9 +161,9 @@
*/
public void testAccessWeightSum() {
LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum);
- TextView weight02 = (TextView) mActivity.findViewById(R.id.weight_0_2);
- TextView weight05 = (TextView) mActivity.findViewById(R.id.weight_0_5);
- TextView weight03 = (TextView) mActivity.findViewById(R.id.weight_0_3);
+ TextView weight02 = (TextView) parent.findViewById(R.id.weight_0_2);
+ TextView weight05 = (TextView) parent.findViewById(R.id.weight_0_5);
+ TextView weight03 = (TextView) parent.findViewById(R.id.weight_0_3);
assertNotNull(parent);
assertNotNull(weight02);
@@ -399,6 +408,182 @@
assertEquals(parent.getWidth(), rightView.getRight());
}
+ public void testVerticalCenterGravityOnHorizontalLayout() {
+ final Instrumentation instrumentation = getInstrumentation();
+ LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum);
+ TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2);
+ TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5);
+ TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3);
+
+ instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+ instrumentation.waitForIdleSync();
+
+ int originalLeftViewRight = leftView.getRight();
+ int originalCenterViewLeft = centerView.getLeft();
+ int originalCenterViewRight = centerView.getRight();
+ int originalRightViewLeft = rightView.getLeft();
+
+ instrumentation.runOnMainSync(() -> parent.setVerticalGravity(Gravity.CENTER_VERTICAL));
+ instrumentation.waitForIdleSync();
+
+ assertEquals(Gravity.CENTER_VERTICAL, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK);
+
+ ViewAsserts.assertVerticalCenterAligned(parent, leftView);
+ ViewAsserts.assertVerticalCenterAligned(parent, centerView);
+ ViewAsserts.assertVerticalCenterAligned(parent, rightView);
+
+ final int parentHeight = parent.getHeight();
+
+ int verticalOffset = (parentHeight - leftView.getHeight()) / 2;
+ assertEquals(verticalOffset, leftView.getTop());
+ assertEquals(verticalOffset + leftView.getHeight(), leftView.getBottom());
+ assertEquals(0, leftView.getLeft());
+ assertEquals(originalLeftViewRight, leftView.getRight());
+
+ verticalOffset = (parentHeight - centerView.getHeight()) / 2;
+ assertEquals(verticalOffset, centerView.getTop());
+ assertEquals(verticalOffset + centerView.getHeight(), centerView.getBottom());
+ assertEquals(originalCenterViewLeft, centerView.getLeft());
+ assertEquals(originalCenterViewRight, centerView.getRight());
+
+ verticalOffset = (parentHeight - rightView.getHeight()) / 2;
+ assertEquals(verticalOffset, rightView.getTop());
+ assertEquals(verticalOffset + rightView.getHeight(), rightView.getBottom());
+ assertEquals(originalRightViewLeft, rightView.getLeft());
+ assertEquals(parent.getWidth(), rightView.getRight());
+ }
+
+ public void testBottomGravityOnHorizontalLayout() {
+ final Instrumentation instrumentation = getInstrumentation();
+ LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum);
+ TextView leftView = (TextView) parent.findViewById(R.id.weight_0_2);
+ TextView centerView = (TextView) parent.findViewById(R.id.weight_0_5);
+ TextView rightView = (TextView) parent.findViewById(R.id.weight_0_3);
+
+ instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+ instrumentation.waitForIdleSync();
+
+ int originalLeftViewRight = leftView.getRight();
+ int originalCenterViewLeft = centerView.getLeft();
+ int originalCenterViewRight = centerView.getRight();
+ int originalRightViewLeft = rightView.getLeft();
+
+ instrumentation.runOnMainSync(() -> parent.setVerticalGravity(Gravity.BOTTOM));
+ instrumentation.waitForIdleSync();
+
+ assertEquals(Gravity.BOTTOM, parent.getGravity() & Gravity.VERTICAL_GRAVITY_MASK);
+
+ ViewAsserts.assertBottomAligned(parent, leftView);
+ ViewAsserts.assertBottomAligned(parent, centerView);
+ ViewAsserts.assertBottomAligned(parent, rightView);
+
+ final int parentHeight = parent.getHeight();
+
+ assertEquals(parentHeight - leftView.getHeight(), leftView.getTop());
+ assertEquals(parentHeight, leftView.getBottom());
+ assertEquals(0, leftView.getLeft());
+ assertEquals(originalLeftViewRight, leftView.getRight());
+
+ assertEquals(parentHeight - centerView.getHeight(), centerView.getTop());
+ assertEquals(parentHeight, centerView.getBottom());
+ assertEquals(originalCenterViewLeft, centerView.getLeft());
+ assertEquals(originalCenterViewRight, centerView.getRight());
+
+ assertEquals(parentHeight - rightView.getHeight(), rightView.getTop());
+ assertEquals(parentHeight, rightView.getBottom());
+ assertEquals(originalRightViewLeft, rightView.getLeft());
+ assertEquals(parent.getWidth(), rightView.getRight());
+ }
+
+ public void testHorizontalCenterGravityOnVerticalLayout() {
+ final Instrumentation instrumentation = getInstrumentation();
+ LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum_vertical);
+ TextView topView = (TextView) parent.findViewById(R.id.weight_0_1);
+ TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4);
+ TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5);
+
+ instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+ instrumentation.waitForIdleSync();
+
+ final int parentWidth = parent.getHeight();
+
+ int originalTopViewBottom = topView.getBottom();
+ int originalCenterViewTop = centerView.getTop();
+ int originalCenterViewBottom = centerView.getBottom();
+ int originalBottomViewTop = bottomView.getTop();
+
+ instrumentation.runOnMainSync(() -> parent.setHorizontalGravity(Gravity.CENTER_HORIZONTAL));
+ instrumentation.waitForIdleSync();
+
+ assertEquals(Gravity.CENTER_HORIZONTAL,
+ parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
+
+ ViewAsserts.assertHorizontalCenterAligned(parent, topView);
+ ViewAsserts.assertHorizontalCenterAligned(parent, centerView);
+ ViewAsserts.assertHorizontalCenterAligned(parent, bottomView);
+
+ int horizontalOffset = (parentWidth - topView.getWidth()) / 2;
+ assertEquals(0, topView.getTop());
+ assertEquals(originalTopViewBottom, topView.getBottom());
+ assertEquals(horizontalOffset, topView.getLeft());
+ assertEquals(horizontalOffset + topView.getWidth(), topView.getRight());
+
+ horizontalOffset = (parentWidth - centerView.getWidth()) / 2;
+ assertEquals(originalCenterViewTop, centerView.getTop());
+ assertEquals(originalCenterViewBottom, centerView.getBottom());
+ assertEquals(horizontalOffset, centerView.getLeft());
+ assertEquals(horizontalOffset + centerView.getWidth(), centerView.getRight());
+
+ horizontalOffset = (parentWidth - bottomView.getWidth()) / 2;
+ assertEquals(originalBottomViewTop, bottomView.getTop());
+ assertEquals(parent.getHeight(), bottomView.getBottom());
+ assertEquals(horizontalOffset, bottomView.getLeft());
+ assertEquals(horizontalOffset + bottomView.getWidth(), bottomView.getRight());
+ }
+
+ public void testRightGravityOnVerticalLayout() {
+ final Instrumentation instrumentation = getInstrumentation();
+ LinearLayout parent = (LinearLayout) mActivity.findViewById(R.id.weightsum_vertical);
+ TextView topView = (TextView) parent.findViewById(R.id.weight_0_1);
+ TextView centerView = (TextView) parent.findViewById(R.id.weight_0_4);
+ TextView bottomView = (TextView) parent.findViewById(R.id.weight_0_5);
+
+ instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+ instrumentation.waitForIdleSync();
+
+ final int parentWidth = parent.getHeight();
+
+ int originalTopViewBottom = topView.getBottom();
+ int originalCenterViewTop = centerView.getTop();
+ int originalCenterViewBottom = centerView.getBottom();
+ int originalBottomViewTop = bottomView.getTop();
+
+ instrumentation.runOnMainSync(() -> parent.setHorizontalGravity(Gravity.RIGHT));
+ instrumentation.waitForIdleSync();
+
+ assertEquals(Gravity.RIGHT,
+ parent.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
+
+ ViewAsserts.assertRightAligned(parent, topView);
+ ViewAsserts.assertRightAligned(parent, centerView);
+ ViewAsserts.assertRightAligned(parent, bottomView);
+
+ assertEquals(0, topView.getTop());
+ assertEquals(originalTopViewBottom, topView.getBottom());
+ assertEquals(parentWidth - topView.getWidth(), topView.getLeft());
+ assertEquals(parentWidth, topView.getRight());
+
+ assertEquals(originalCenterViewTop, centerView.getTop());
+ assertEquals(originalCenterViewBottom, centerView.getBottom());
+ assertEquals(parentWidth - centerView.getWidth(), centerView.getLeft());
+ assertEquals(parentWidth, centerView.getRight());
+
+ assertEquals(originalBottomViewTop, bottomView.getTop());
+ assertEquals(parent.getHeight(), bottomView.getBottom());
+ assertEquals(parentWidth - bottomView.getWidth(), bottomView.getLeft());
+ assertEquals(parentWidth, bottomView.getRight());
+ }
+
private void checkBounds(final ViewGroup viewGroup, final View view,
final CountDownLatch countDownLatch, final int left, final int top,
final int width, final int height) {
@@ -471,6 +656,523 @@
countDownLatch3.await(500, TimeUnit.MILLISECONDS);
}
+ private void verifyVisualsOfVerticalLayoutWithDivider(LinearLayout parent,
+ int expectedDividerPositionMask,
+ int expectedDividerSize, @ColorInt int expectedDividerColor,
+ int expectedDividerPadding) {
+ final int parentWidth = parent.getWidth();
+ final int parentHeight = parent.getHeight();
+
+ final boolean expectingTopDivider =
+ (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0;
+ final boolean expectingMiddleDivider =
+ (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0;
+ final boolean expectingBottomDivider =
+ (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0;
+ final int expectedDividerCount = (expectingTopDivider ? 1 : 0)
+ + (expectingMiddleDivider ? 1 : 0) + (expectingBottomDivider ? 1 : 0);
+
+ final int expectedChildHeight =
+ (parentHeight - expectedDividerCount * expectedDividerSize) / 2;
+
+ final int expectedTopChildTop = expectingTopDivider ? expectedDividerSize : 0;
+ TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent,
+ new Rect(0, expectedTopChildTop, parentWidth,
+ expectedTopChildTop + expectedChildHeight),
+ Color.BLUE, 1, true);
+
+ final int expectedBottomChildBottom =
+ expectingBottomDivider ? parentHeight - expectedDividerSize : parentHeight;
+ TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent,
+ new Rect(0, expectedBottomChildBottom - expectedChildHeight, parentWidth,
+ expectedBottomChildBottom),
+ Color.GREEN, 1, true);
+
+ if (expectedDividerSize == 0) {
+ return;
+ }
+
+ // Do we expect top divider?
+ if (expectingTopDivider) {
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of top divider is " + TestUtils.formatColorToHex(expectedDividerColor),
+ parent,
+ new Rect(expectedDividerPadding, 0, parentWidth - expectedDividerPadding,
+ expectedDividerSize),
+ expectedDividerColor, 1, true);
+ TestUtils.assertRegionPixelsOfColor("Region of left padding of top divider is yellow",
+ parent,
+ new Rect(0, 0, expectedDividerPadding, expectedDividerSize),
+ Color.YELLOW, 1, true);
+ TestUtils.assertRegionPixelsOfColor("Region of right padding of top divider is yellow",
+ parent,
+ new Rect(parentWidth - expectedDividerPadding, 0, parentWidth,
+ expectedDividerSize),
+ Color.YELLOW, 1, true);
+ }
+
+ // Do we expect middle divider?
+ if (expectingMiddleDivider) {
+ final int expectedMiddleDividerTop = expectedTopChildTop + expectedChildHeight;
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of middle divider is " +
+ TestUtils.formatColorToHex(expectedDividerColor),
+ parent,
+ new Rect(expectedDividerPadding, expectedMiddleDividerTop,
+ parentWidth - expectedDividerPadding,
+ expectedMiddleDividerTop + expectedDividerSize),
+ expectedDividerColor, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of left padding of middle divider is yellow",
+ parent,
+ new Rect(0, expectedMiddleDividerTop, expectedDividerPadding,
+ expectedMiddleDividerTop + expectedDividerSize),
+ Color.YELLOW, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of right padding of middle divider is yellow",
+ parent,
+ new Rect(parentWidth - expectedDividerPadding, expectedMiddleDividerTop,
+ parentWidth, expectedMiddleDividerTop + expectedDividerSize),
+ Color.YELLOW, 1, true);
+ }
+
+ // Do we expect bottom divider?
+ if (expectingBottomDivider) {
+ final int expectedBottomDividerTop = expectedBottomChildBottom;
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of bottom divider is " +
+ TestUtils.formatColorToHex(expectedDividerColor),
+ parent,
+ new Rect(expectedDividerPadding, expectedBottomDividerTop,
+ parentWidth - expectedDividerPadding,
+ expectedBottomDividerTop + expectedDividerSize),
+ expectedDividerColor, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of left padding of bottom divider is yellow",
+ parent,
+ new Rect(0, expectedBottomDividerTop, expectedDividerPadding,
+ expectedBottomDividerTop + expectedDividerSize),
+ Color.YELLOW, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of right padding of bottom divider is yellow",
+ parent,
+ new Rect(parentWidth - expectedDividerPadding, expectedBottomDividerTop,
+ parentWidth, expectedBottomDividerTop + expectedDividerSize),
+ Color.YELLOW, 1, true);
+ }
+ }
+
+ /**
+ * layout of vertical LinearLayout.
+ * -----------------------------------
+ * | ------------------------------- |
+ * | | child1 | |
+ * | ------------------------------- |
+ * | - - - - - - divider - - - - - - |
+ * | ------------------------------- |
+ * | | child2 | |
+ * | ------------------------------- |
+ * -----------------------------------
+ *
+ * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled
+ * with blue. Divider is red at the beginning. Throughout this method we reconfigure the
+ * visibility, drawable and paddings of the divider and verify the overall visuals of the
+ * container.
+ */
+ public void testDividersInVerticalLayout() {
+ final LinearLayout parent =
+ (LinearLayout) mActivity.findViewById(R.id.vertical_with_divider);
+
+ final Instrumentation instrumentation = getInstrumentation();
+
+ final Resources res = mActivity.getResources();
+ final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size);
+ final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding);
+
+ assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers());
+ assertEquals(dividerPadding, parent.getDividerPadding());
+ final Drawable dividerDrawable = parent.getDividerDrawable();
+ TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable,
+ dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
+ false, Color.RED, 1, true);
+
+ // Test the initial visuals of the entire parent
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Change the divider to magenta
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerDrawable(
+ mActivity.getDrawable(R.drawable.linear_layout_divider_magenta)));
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.MAGENTA, dividerPadding);
+
+ // Change the divider to null (no divider effectively)
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerDrawable(null));
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ 0, Color.TRANSPARENT, 0);
+
+ // Change the divider back to red
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerDrawable(
+ mActivity.getDrawable(R.drawable.linear_layout_divider_red)));
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Change the padding to half the original size
+ final int halfPadding = dividerPadding / 2;
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerPadding(halfPadding));
+ assertEquals(halfPadding, parent.getDividerPadding());
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, halfPadding);
+
+ // Change the padding to twice the original size
+ final int doublePadding = dividerPadding * 2;
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerPadding(doublePadding));
+ assertEquals(doublePadding, parent.getDividerPadding());
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, doublePadding);
+
+ // And back to the original padding
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerPadding(dividerPadding));
+ assertEquals(dividerPadding, parent.getDividerPadding());
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Set show dividers to NONE (no divider effectively)
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE));
+ assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE,
+ 0, Color.TRANSPARENT, 0);
+
+ // Show only top divider
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING));
+ assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show only bottom divider
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show top and bottom dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+ parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show top and middle dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE));
+ assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+ parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show middle and bottom dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+ parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show top, middle and bottom dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+ | LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+ | LinearLayout.SHOW_DIVIDER_END,
+ parent.getShowDividers());
+ verifyVisualsOfVerticalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+ | LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+ }
+
+ private void verifyVisualsOfHorizontalLayoutWithDivider(LinearLayout parent,
+ int expectedDividerPositionMask,
+ int expectedDividerSize, @ColorInt int expectedDividerColor,
+ int expectedDividerPadding) {
+ final int parentWidth = parent.getWidth();
+ final int parentHeight = parent.getHeight();
+
+ final boolean expectingLeftDivider =
+ (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_BEGINNING) != 0;
+ final boolean expectingMiddleDivider =
+ (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_MIDDLE) != 0;
+ final boolean expectingRightDivider =
+ (expectedDividerPositionMask & LinearLayout.SHOW_DIVIDER_END) != 0;
+ final int expectedDividerCount = (expectingLeftDivider ? 1 : 0)
+ + (expectingMiddleDivider ? 1 : 0) + (expectingRightDivider ? 1 : 0);
+
+ final int expectedChildWidth =
+ (parentWidth - expectedDividerCount * expectedDividerSize) / 2;
+
+ final int expectedLeftChildLeft = expectingLeftDivider ? expectedDividerSize : 0;
+ TestUtils.assertRegionPixelsOfColor("Region of first child is blue", parent,
+ new Rect(expectedLeftChildLeft, 0,
+ expectedLeftChildLeft + expectedChildWidth, parentHeight),
+ Color.BLUE, 1, true);
+
+ final int expectedRightChildRight =
+ expectingRightDivider ? parentWidth - expectedDividerSize : parentWidth;
+ TestUtils.assertRegionPixelsOfColor("Region of second child is green", parent,
+ new Rect(expectedRightChildRight - expectedChildWidth, 0, expectedRightChildRight,
+ parentHeight),
+ Color.GREEN, 1, true);
+
+ if (expectedDividerSize == 0) {
+ return;
+ }
+
+ // Do we expect left divider?
+ if (expectingLeftDivider) {
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of left divider is " + TestUtils.formatColorToHex(expectedDividerColor),
+ parent,
+ new Rect(0, expectedDividerPadding, expectedDividerSize,
+ parentHeight - expectedDividerPadding),
+ expectedDividerColor, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of top padding of left divider is yellow",
+ parent,
+ new Rect(0, 0, expectedDividerSize, expectedDividerPadding),
+ Color.YELLOW, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of bottom padding of left divider is yellow",
+ parent,
+ new Rect(0, parentHeight - expectedDividerPadding, expectedDividerSize,
+ parentHeight),
+ Color.YELLOW, 1, true);
+ }
+
+ // Do we expect middle divider?
+ if (expectingMiddleDivider) {
+ final int expectedMiddleDividerLeft = expectedLeftChildLeft + expectedChildWidth;
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of middle divider is " +
+ TestUtils.formatColorToHex(expectedDividerColor),
+ parent,
+ new Rect(expectedMiddleDividerLeft, expectedDividerPadding,
+ expectedMiddleDividerLeft + expectedDividerSize,
+ parentHeight - expectedDividerPadding),
+ expectedDividerColor, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of top padding of middle divider is yellow",
+ parent,
+ new Rect(expectedMiddleDividerLeft, 0,
+ expectedMiddleDividerLeft + expectedDividerSize,
+ expectedDividerPadding),
+ Color.YELLOW, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of bottom padding of middle divider is yellow",
+ parent,
+ new Rect(expectedMiddleDividerLeft, parentHeight - expectedDividerPadding,
+ expectedMiddleDividerLeft + expectedDividerSize, parentHeight),
+ Color.YELLOW, 1, true);
+ }
+
+ // Do we expect right divider?
+ if (expectingRightDivider) {
+ final int expectedRightDividerLeft = expectedRightChildRight;
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of right divider is " +
+ TestUtils.formatColorToHex(expectedDividerColor),
+ parent,
+ new Rect(expectedRightDividerLeft, expectedDividerPadding,
+ expectedRightDividerLeft + expectedDividerSize,
+ parentHeight - expectedDividerPadding),
+ expectedDividerColor, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of top padding of right divider is yellow",
+ parent,
+ new Rect(expectedRightDividerLeft, 0,
+ expectedRightDividerLeft + expectedDividerSize,
+ expectedDividerPadding),
+ Color.YELLOW, 1, true);
+ TestUtils.assertRegionPixelsOfColor(
+ "Region of bottom padding of right divider is yellow",
+ parent,
+ new Rect(expectedRightDividerLeft, parentHeight - expectedDividerPadding,
+ expectedRightDividerLeft + expectedDividerSize, parentHeight),
+ Color.YELLOW, 1, true);
+ }
+ }
+
+ /**
+ * layout of horizontal LinearLayout.
+ * -----------------------------------
+ * | ------------ | ------------- |
+ * | | | | | |
+ * | | | d | | |
+ * | | | i | | |
+ * | | | v | | |
+ * | | child1 | i | child2 | |
+ * | | | d | | |
+ * | | | e | | |
+ * | | | r | | |
+ * | | | | | |
+ * | ------------ | ------------- |
+ * -----------------------------------
+ *
+ * Parent is filled with yellow color. Child 1 is filled with green and child 2 is filled
+ * with blue. Divider is red at the beginning. Throughout this method we reconfigure the
+ * visibility, drawable and paddings of the divider and verify the overall visuals of the
+ * container.
+ */
+ public void testDividersInHorizontalLayout() {
+ final LinearLayout parent =
+ (LinearLayout) mActivity.findViewById(R.id.horizontal_with_divider);
+
+ final Instrumentation instrumentation = getInstrumentation();
+
+ instrumentation.runOnMainSync(() -> parent.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+ instrumentation.waitForIdleSync();
+
+ final Resources res = mActivity.getResources();
+ final int dividerSize = res.getDimensionPixelSize(R.dimen.linear_layout_divider_size);
+ final int dividerPadding = res.getDimensionPixelSize(R.dimen.linear_layout_divider_padding);
+
+ assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE, parent.getShowDividers());
+ assertEquals(dividerPadding, parent.getDividerPadding());
+ final Drawable dividerDrawable = parent.getDividerDrawable();
+ TestUtils.assertAllPixelsOfColor("Divider is red", dividerDrawable,
+ dividerDrawable.getIntrinsicWidth(), dividerDrawable.getIntrinsicHeight(),
+ false, Color.RED, 1, true);
+
+ // Test the initial visuals of the entire parent
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Change the divider to magenta
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerDrawable(
+ mActivity.getDrawable(R.drawable.linear_layout_divider_magenta)));
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.MAGENTA, dividerPadding);
+
+ // Change the divider to null (no divider effectively)
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerDrawable(null));
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ 0, Color.TRANSPARENT, 0);
+
+ // Change the divider back to red
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerDrawable(
+ mActivity.getDrawable(R.drawable.linear_layout_divider_red)));
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Change the padding to half the original size
+ final int halfPadding = dividerPadding / 2;
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerPadding(halfPadding));
+ assertEquals(halfPadding, parent.getDividerPadding());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, halfPadding);
+
+ // Change the padding to twice the original size
+ final int doublePadding = dividerPadding * 2;
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerPadding(doublePadding));
+ assertEquals(doublePadding, parent.getDividerPadding());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, doublePadding);
+
+ // And back to the original padding
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setDividerPadding(dividerPadding));
+ assertEquals(dividerPadding, parent.getDividerPadding());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Set show dividers to NONE (no divider effectively)
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE));
+ assertEquals(LinearLayout.SHOW_DIVIDER_NONE, parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_NONE,
+ 0, Color.TRANSPARENT, 0);
+
+ // Show only left divider
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING));
+ assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING, parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_BEGINNING,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show only right divider
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(LinearLayout.SHOW_DIVIDER_END, parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent, LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show left and right dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+ parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show left and middle dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE));
+ assertEquals(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+ parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show middle and right dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+ parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_MIDDLE | LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+
+ // Show left, middle and right dividers
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, parent,
+ () -> parent.setShowDividers(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+ | LinearLayout.SHOW_DIVIDER_END));
+ assertEquals(
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+ | LinearLayout.SHOW_DIVIDER_END,
+ parent.getShowDividers());
+ verifyVisualsOfHorizontalLayoutWithDivider(parent,
+ LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE
+ | LinearLayout.SHOW_DIVIDER_END,
+ dividerSize, Color.RED, dividerPadding);
+ }
+
private class MockListView extends ListView {
private final static int DEFAULT_CHILD_BASE_LINE = 1;
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
index b50f8c9..8182e91 100644
--- a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -372,17 +372,6 @@
// Make sure that the modality of the popup window is set up correctly
assertEquals("Popup window modality", setupAsModal, mPopupWindow.isModal());
- // Determine the location of the popup on the screen so that we can emulate
- // a tap outside of its bounds to dismiss it
- final int[] popupOnScreenXY = new int[2];
- final Rect rect = new Rect();
- mPopupWindow.getListView().getLocationOnScreen(popupOnScreenXY);
- mPopupWindow.getBackground().getPadding(rect);
-
- int emulatedTapX = popupOnScreenXY[0] - rect.left - 20;
- int emulatedTapY = popupOnScreenXY[1] + mPopupWindow.getListView().getHeight() +
- rect.top + rect.bottom + 20;
-
// The logic below uses Instrumentation to emulate a tap outside the bounds of the
// displayed list popup window. This tap is then treated by the framework to be "split" as
// the ACTION_OUTSIDE for the popup itself, as well as DOWN / MOVE / UP for the underlying
@@ -392,29 +381,12 @@
// of Instrumentation is necessary here since Espresso's actions operate at the level
// of view or data. Also, we don't want to use View.dispatchTouchEvent directly as
// that would require emulation of two separate sequences as well.
-
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-
- // Inject DOWN event
- long downTime = SystemClock.uptimeMillis();
- MotionEvent eventDown = MotionEvent.obtain(
- downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
- instrumentation.sendPointerSync(eventDown);
-
- // Inject MOVE event
- long moveTime = SystemClock.uptimeMillis();
- MotionEvent eventMove = MotionEvent.obtain(
- moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
- instrumentation.sendPointerSync(eventMove);
-
- // Inject UP event
- long upTime = SystemClock.uptimeMillis();
- MotionEvent eventUp = MotionEvent.obtain(
- upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
- instrumentation.sendPointerSync(eventUp);
-
- // Wait for the system to process all events in the queue
- instrumentation.waitForIdleSync();
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final ListView popupListView = mPopupWindow.getListView();
+ final Rect rect = new Rect();
+ mPopupWindow.getBackground().getPadding(rect);
+ ViewTestUtils.emulateTapOnScreen(instrumentation, popupListView,
+ -rect.left - 20, popupListView.getHeight() + rect.top + rect.bottom + 20);
// At this point our popup should not be showing and should have notified its
// dismiss listener
@@ -668,40 +640,6 @@
verifyNoMoreInteractions(mPopupWindowBuilder.mOnDismissListener);
}
- /**
- * Emulates a drag-down gestures by injecting ACTION events with {@link Instrumentation}.
- */
- private void emulateDragDownGesture(int emulatedX, int emulatedStartY, int swipeAmount) {
- // The logic below uses Instrumentation to emulate a swipe / drag gesture to bring up
- // the popup content.
-
- // Inject DOWN event
- long downTime = SystemClock.uptimeMillis();
- MotionEvent eventDown = MotionEvent.obtain(
- downTime, downTime, MotionEvent.ACTION_DOWN, emulatedX, emulatedStartY, 1);
- mInstrumentation.sendPointerSync(eventDown);
-
- // Inject a sequence of MOVE events that emulate a "swipe down" gesture
- for (int i = 0; i < 10; i++) {
- long moveTime = SystemClock.uptimeMillis();
- final int moveY = emulatedStartY + swipeAmount * i / 10;
- MotionEvent eventMove = MotionEvent.obtain(
- moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedX, moveY, 1);
- mInstrumentation.sendPointerSync(eventMove);
- // sleep for a bit to emulate a 200ms swipe
- SystemClock.sleep(20);
- }
-
- // Inject UP event
- long upTime = SystemClock.uptimeMillis();
- MotionEvent eventUp = MotionEvent.obtain(
- upTime, upTime, MotionEvent.ACTION_UP, emulatedX, emulatedStartY + swipeAmount, 1);
- mInstrumentation.sendPointerSync(eventUp);
-
- // Wait for the system to process all events in the queue
- mInstrumentation.waitForIdleSync();
- }
-
public void testCreateOnDragListener() throws Throwable {
// In this test we want precise control over the height of the popup content since
// we need to know by how much to swipe down to end the emulated gesture over the
@@ -738,7 +676,8 @@
int swipeAmount = 2 * popupRowHeight;
// Emulate drag-down gesture with a sequence of motion events
- emulateDragDownGesture(emulatedX, emulatedStartY, swipeAmount);
+ ViewTestUtils.emulateDragGesture(getInstrumentation(), emulatedX, emulatedStartY,
+ 0, swipeAmount);
// We expect the swipe / drag gesture to result in clicking the second item in our list.
verify(mPopupWindowBuilder.mOnItemClickListener, times(1)).onItemClick(
@@ -952,7 +891,8 @@
if (mHasItemSelectedListener) {
mOnItemSelectedListener = mock(AdapterView.OnItemSelectedListener.class);
mPopupWindow.setOnItemSelectedListener(mOnItemSelectedListener);
- mPopupWindow.setListSelector(mActivity.getDrawable(R.drawable.red_fill));
+ mPopupWindow.setListSelector(
+ mActivity.getDrawable(R.drawable.red_translucent_fill));
}
if (mHasDismissListener) {
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
new file mode 100644
index 0000000..f93a1da
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.NumberPicker;
+
+/**
+ * A minimal application for {@link NumberPicker} test.
+ */
+public class NumberPickerCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.numberpicker_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
new file mode 100644
index 0000000..a7945e3
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.widget.cts;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import android.widget.NumberPicker;
+import android.widget.cts.util.ViewTestUtils;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.*;
+
+@SmallTest
+public class NumberPickerTest extends ActivityInstrumentationTestCase2<NumberPickerCtsActivity> {
+ private static final String[] NUMBER_NAMES3 = {"One", "Two", "Three"};
+ private static final String[] NUMBER_NAMES_ALT3 = {"Three", "Four", "Five"};
+ private static final String[] NUMBER_NAMES5 = {"One", "Two", "Three", "Four", "Five"};
+
+ private Instrumentation mInstrumentation;
+ private NumberPickerCtsActivity mActivity;
+ private NumberPicker mNumberPicker;
+
+ public NumberPickerTest() {
+ super("android.widget.cts", NumberPickerCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mNumberPicker = (NumberPicker) mActivity.findViewById(R.id.number_picker);
+ }
+
+ @UiThreadTest
+ public void testConstructor() {
+ new NumberPicker(mActivity);
+
+ new NumberPicker(mActivity, null);
+
+ new NumberPicker(mActivity, null, android.R.attr.numberPickerStyle);
+
+ new NumberPicker(mActivity, null, 0, android.R.style.Widget_Material_Light_NumberPicker);
+ }
+
+ private void verifyDisplayedValues(String[] expected) {
+ final String[] displayedValues = mNumberPicker.getDisplayedValues();
+ assertEquals(expected.length, displayedValues.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], displayedValues[i]);
+ }
+ }
+
+ public void testSetDisplayedValuesRangeMatch() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(10);
+ mNumberPicker.setMaxValue(12);
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+ });
+
+ assertEquals(10, mNumberPicker.getMinValue());
+ assertEquals(12, mNumberPicker.getMaxValue());
+ verifyDisplayedValues(NUMBER_NAMES3);
+
+ // Set a different displayed values array, but still matching the min/max range
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+ });
+
+ assertEquals(10, mNumberPicker.getMinValue());
+ assertEquals(12, mNumberPicker.getMaxValue());
+ verifyDisplayedValues(NUMBER_NAMES_ALT3);
+
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(24);
+ mNumberPicker.setMaxValue(26);
+ });
+
+ assertEquals(24, mNumberPicker.getMinValue());
+ assertEquals(26, mNumberPicker.getMaxValue());
+ verifyDisplayedValues(NUMBER_NAMES_ALT3);
+ }
+
+ public void testSetDisplayedValuesRangeMismatch() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(10);
+ mNumberPicker.setMaxValue(14);
+ });
+ assertEquals(10, mNumberPicker.getMinValue());
+ assertEquals(14, mNumberPicker.getMaxValue());
+
+ // Try setting too few displayed entries
+ mInstrumentation.runOnMainSync(() -> {
+ try {
+ // This is expected to fail since the displayed values only has three entries,
+ // while the min/max range has five.
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+ fail("The size of the displayed values array must be equal to min/max range!");
+ } catch (Exception e) {
+ // We are expecting to catch an exception. Set displayed values to an array that
+ // matches the min/max range.
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES5);
+ }
+ });
+ }
+
+ public void testSelectionDisplayedValueFromDisplayedValues() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(1);
+ mNumberPicker.setMaxValue(3);
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+ });
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals(NUMBER_NAMES3[0],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+ assertTrue(TextUtils.equals(NUMBER_NAMES3[1],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+ assertTrue(TextUtils.equals(NUMBER_NAMES3[2],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ // Switch to a different displayed values array
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+ });
+ assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[2],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[0],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+ assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[1],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+ }
+
+ public void testSelectionDisplayedValueFromFormatter() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(0);
+ mNumberPicker.setMaxValue(4);
+ mNumberPicker.setFormatter((int value) -> "entry " + value);
+ });
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(0));
+ assertTrue(TextUtils.equals("entry 0",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals("entry 1",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+ assertTrue(TextUtils.equals("entry 2",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+ assertTrue(TextUtils.equals("entry 3",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(4));
+ assertTrue(TextUtils.equals("entry 4",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ // Switch to a different formatter
+ mInstrumentation.runOnMainSync(
+ () -> mNumberPicker.setFormatter((int value) -> "row " + value));
+ // Check that the currently selected value has new displayed value
+ assertTrue(TextUtils.equals("row 4",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ // and check a couple more values for the new formatting
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(0));
+ assertTrue(TextUtils.equals("row 0",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals("row 1",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+ }
+
+
+ public void testSelectionDisplayedValuePrecedence() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(1);
+ mNumberPicker.setMaxValue(3);
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+ mNumberPicker.setFormatter((int value) -> "entry " + value);
+ });
+
+ // According to the widget documentation, displayed values take precedence over formatter
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals(NUMBER_NAMES3[0],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+ assertTrue(TextUtils.equals(NUMBER_NAMES3[1],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+ assertTrue(TextUtils.equals(NUMBER_NAMES3[2],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ // Set displayed values to null and test that the widget is using the formatter
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setDisplayedValues(null));
+ assertTrue(TextUtils.equals("entry 3",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals("entry 1",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(2));
+ assertTrue(TextUtils.equals("entry 2",
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ // Set a different displayed values array and test that it's taking precedence
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3));
+ assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[1],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(1));
+ assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[0],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(3));
+ assertTrue(TextUtils.equals(NUMBER_NAMES_ALT3[2],
+ mNumberPicker.getDisplayedValueForCurrentSelection()));
+ }
+
+ public void testAccessValue() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(20);
+ mNumberPicker.setMaxValue(22);
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES3);
+ });
+
+ final NumberPicker.OnValueChangeListener mockValueChangeListener =
+ mock(NumberPicker.OnValueChangeListener.class);
+ mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(21));
+ assertEquals(21, mNumberPicker.getValue());
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(20));
+ assertEquals(20, mNumberPicker.getValue());
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(22));
+ assertEquals(22, mNumberPicker.getValue());
+
+ // Check trying to set value out of min/max range
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(10));
+ assertEquals(20, mNumberPicker.getValue());
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(100));
+ assertEquals(22, mNumberPicker.getValue());
+
+ // Since all changes to value are via API calls, we should have no interactions /
+ // callbacks on our listener.
+ verifyZeroInteractions(mockValueChangeListener);
+ }
+
+ public void testInteractionWithSwipeDown() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(6);
+ mNumberPicker.setMaxValue(8);
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+ });
+
+ final NumberPicker.OnValueChangeListener mockValueChangeListener =
+ mock(NumberPicker.OnValueChangeListener.class);
+ mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+ final NumberPicker.OnScrollListener mockScrollListener =
+ mock(NumberPicker.OnScrollListener.class);
+ mNumberPicker.setOnScrollListener(mockScrollListener);
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(7));
+ assertEquals(7, mNumberPicker.getValue());
+
+ // Swipe down across our number picker
+ final int[] numberPickerLocationOnScreen = new int[2];
+ mNumberPicker.getLocationOnScreen(numberPickerLocationOnScreen);
+
+ ViewTestUtils.emulateDragGesture(mInstrumentation,
+ numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2,
+ numberPickerLocationOnScreen[1] + 1,
+ 0,
+ mNumberPicker.getHeight() - 2);
+
+ // At this point we expect that the drag-down gesture has selected the value
+ // that was "above" the previously selected one, and that our value change listener
+ // has been notified of that change exactly once.
+ assertEquals(6, mNumberPicker.getValue());
+ verify(mockValueChangeListener, times(1)).onValueChange(mNumberPicker, 7, 6);
+ verifyNoMoreInteractions(mockValueChangeListener);
+
+ // We expect that our scroll listener will be called with specific state changes.
+ InOrder inOrder = inOrder(mockScrollListener);
+ inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+ NumberPicker.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
+ inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+ NumberPicker.OnScrollListener.SCROLL_STATE_IDLE);
+ verifyNoMoreInteractions(mockScrollListener);
+ }
+
+ public void testInteractionWithSwipeUp() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(10);
+ mNumberPicker.setMaxValue(12);
+ mNumberPicker.setDisplayedValues(NUMBER_NAMES_ALT3);
+ });
+
+ final NumberPicker.OnValueChangeListener mockValueChangeListener =
+ mock(NumberPicker.OnValueChangeListener.class);
+ mNumberPicker.setOnValueChangedListener(mockValueChangeListener);
+
+ final NumberPicker.OnScrollListener mockScrollListener =
+ mock(NumberPicker.OnScrollListener.class);
+ mNumberPicker.setOnScrollListener(mockScrollListener);
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setValue(11));
+ assertEquals(11, mNumberPicker.getValue());
+
+ // Swipe up across our number picker
+ final int[] numberPickerLocationOnScreen = new int[2];
+ mNumberPicker.getLocationOnScreen(numberPickerLocationOnScreen);
+
+ ViewTestUtils.emulateDragGesture(mInstrumentation,
+ numberPickerLocationOnScreen[0] + mNumberPicker.getWidth() / 2,
+ numberPickerLocationOnScreen[1] + mNumberPicker.getHeight() - 1,
+ 0,
+ - (mNumberPicker.getHeight() - 2));
+
+ // At this point we expect that the drag-up gesture has selected the value
+ // that was "below" the previously selected one, and that our value change listener
+ // has been notified of that change exactly once.
+ assertEquals(12, mNumberPicker.getValue());
+ verify(mockValueChangeListener, times(1)).onValueChange(mNumberPicker, 11, 12);
+ verifyNoMoreInteractions(mockValueChangeListener);
+
+ // We expect that our scroll listener will be called with specific state changes.
+ InOrder inOrder = inOrder(mockScrollListener);
+ inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+ NumberPicker.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
+ inOrder.verify(mockScrollListener).onScrollStateChange(mNumberPicker,
+ NumberPicker.OnScrollListener.SCROLL_STATE_IDLE);
+ verifyNoMoreInteractions(mockScrollListener);
+ }
+
+ public void testAccessWrapSelectorValue() {
+ mInstrumentation.runOnMainSync(() -> {
+ mNumberPicker.setMinValue(100);
+ mNumberPicker.setMaxValue(200);
+ });
+ // As specified in the Javadocs of NumberPicker.setWrapSelectorWheel, when min/max
+ // range is larger than what the widget is showing, the selector wheel is enabled.
+ assertTrue(mNumberPicker.getWrapSelectorWheel());
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setWrapSelectorWheel(false));
+ assertFalse(mNumberPicker.getWrapSelectorWheel());
+
+ mInstrumentation.runOnMainSync(() -> mNumberPicker.setWrapSelectorWheel(true));
+ assertTrue(mNumberPicker.getWrapSelectorWheel());
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index ee38448..aa37127 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -30,6 +30,7 @@
import android.view.View;
import android.widget.EditText;
import android.widget.PopupMenu;
+import android.widget.cts.util.ViewTestUtils;
import static org.mockito.Mockito.*;
@@ -183,15 +184,7 @@
runTestOnUiThread(() -> mBuilder.show());
mInstrumentation.waitForIdleSync();
- // Determine the location of the anchor on the screen so that we can emulate
- // a tap outside of the popup bounds to dismiss the popup
- final int[] anchorOnScreenXY = new int[2];
- mBuilder.mAnchor.getLocationOnScreen(anchorOnScreenXY);
-
- int emulatedTapX = anchorOnScreenXY[0] + 10;
- int emulatedTapY = anchorOnScreenXY[1] - 20;
-
- // The logic below uses Instrumentation to emulate a tap outside the bounds of the
+ // The call below uses Instrumentation to emulate a tap outside the bounds of the
// displayed popup menu. This tap is then treated by the framework to be "split" as
// the ACTION_OUTSIDE for the popup itself, as well as DOWN / MOVE / UP for the underlying
// view root if the popup is not modal.
@@ -200,27 +193,7 @@
// of Instrumentation is necessary here since Espresso's actions operate at the level
// of view or data. Also, we don't want to use View.dispatchTouchEvent directly as
// that would require emulation of two separate sequences as well.
-
- // Inject DOWN event
- long downTime = SystemClock.uptimeMillis();
- MotionEvent eventDown = MotionEvent.obtain(
- downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
- mInstrumentation.sendPointerSync(eventDown);
-
- // Inject MOVE event
- long moveTime = SystemClock.uptimeMillis();
- MotionEvent eventMove = MotionEvent.obtain(
- moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
- mInstrumentation.sendPointerSync(eventMove);
-
- // Inject UP event
- long upTime = SystemClock.uptimeMillis();
- MotionEvent eventUp = MotionEvent.obtain(
- upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
- mInstrumentation.sendPointerSync(eventUp);
-
- // Wait for the system to process all events in the queue
- mInstrumentation.waitForIdleSync();
+ ViewTestUtils.emulateTapOnScreen(mInstrumentation, mBuilder.mAnchor, 10, -20);
// At this point our popup should have notified its dismiss listener
verify(mBuilder.mOnDismissListener, times(1)).onDismiss(mPopupMenu);
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 96b37d3..80e5691 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -20,12 +20,14 @@
import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.transition.Transition;
import android.transition.Transition.TransitionListener;
import android.transition.TransitionValues;
@@ -51,6 +53,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+@SmallTest
public class PopupWindowTest extends
ActivityInstrumentationTestCase2<PopupWindowCtsActivity> {
private Instrumentation mInstrumentation;
@@ -84,6 +87,8 @@
new PopupWindow(mActivity, null, android.R.attr.popupWindowStyle);
+ new PopupWindow(mActivity, null, 0, android.R.style.Widget_Material_Light_PopupWindow);
+
mPopupWindow = new PopupWindow();
assertEquals(0, mPopupWindow.getWidth());
assertEquals(0, mPopupWindow.getHeight());
@@ -575,6 +580,8 @@
// Do not attach within the decor; we will be measuring location
// with regard to screen coordinates.
mPopupWindow.setAttachedInDecor(false);
+ assertFalse(mPopupWindow.isAttachedInDecor());
+
final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
final int xOff = 10;
@@ -656,42 +663,73 @@
public void testGetMaxAvailableHeight() {
mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+ final Point point = new Point();
+ getDisplay().getSize(point);
+ final int displayHeight = point.y;
View anchorView = mActivity.findViewById(R.id.anchor_upper);
- int avaliable = getDisplay().getHeight() - anchorView.getHeight();
+ int available = displayHeight - anchorView.getHeight();
int maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
+ int maxAvailableHeightIgnoringBottomDecoration =
+ mPopupWindow.getMaxAvailableHeight(anchorView, 0, true);
assertTrue(maxAvailableHeight > 0);
- assertTrue(maxAvailableHeight <= avaliable);
+ assertTrue(maxAvailableHeight <= available);
+ assertTrue(maxAvailableHeightIgnoringBottomDecoration >= maxAvailableHeight);
+ assertTrue(maxAvailableHeightIgnoringBottomDecoration <= available);
+
int maxAvailableHeightWithOffset = mPopupWindow.getMaxAvailableHeight(anchorView, 2);
assertEquals(maxAvailableHeight - 2, maxAvailableHeightWithOffset);
+
maxAvailableHeightWithOffset =
mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight);
assertTrue(maxAvailableHeightWithOffset > 0);
- assertTrue(maxAvailableHeightWithOffset <= avaliable);
+ assertTrue(maxAvailableHeightWithOffset <= available);
+
maxAvailableHeightWithOffset =
mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight / 2 - 1);
assertTrue(maxAvailableHeightWithOffset > 0);
- assertTrue(maxAvailableHeightWithOffset <= avaliable);
+ assertTrue(maxAvailableHeightWithOffset <= available);
+
maxAvailableHeightWithOffset = mPopupWindow.getMaxAvailableHeight(anchorView, -1);
assertTrue(maxAvailableHeightWithOffset > 0);
- assertTrue(maxAvailableHeightWithOffset <= avaliable);
+ assertTrue(maxAvailableHeightWithOffset <= available);
+
+ int maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+ mPopupWindow.getMaxAvailableHeight(anchorView, 2, true);
+ assertEquals(maxAvailableHeightIgnoringBottomDecoration - 2,
+ maxAvailableHeightWithOffsetIgnoringBottomDecoration);
+
+ maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+ mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight, true);
+ assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration > 0);
+ assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration <= available);
+
+ maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+ mPopupWindow.getMaxAvailableHeight(anchorView, maxAvailableHeight / 2 - 1, true);
+ assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration > 0);
+ assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration <= available);
+
+ maxAvailableHeightWithOffsetIgnoringBottomDecoration =
+ mPopupWindow.getMaxAvailableHeight(anchorView, -1, true);
+ assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration > 0);
+ assertTrue(maxAvailableHeightWithOffsetIgnoringBottomDecoration <= available);
anchorView = mActivity.findViewById(R.id.anchor_lower);
// On some devices the view might actually have larger size than the physical display
// due to chin and content will be laid out as if outside of the display. We need to use
// larger from the display height and the main view height.
- avaliable = Math.max(getDisplay().getHeight(),
+ available = Math.max(displayHeight,
mActivity.findViewById(android.R.id.content).getHeight()) - anchorView.getHeight();
maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
assertTrue(maxAvailableHeight > 0);
- assertTrue(maxAvailableHeight <= avaliable);
+ assertTrue(maxAvailableHeight <= available);
anchorView = mActivity.findViewById(R.id.anchor_middle_left);
- avaliable = getDisplay().getHeight() - anchorView.getHeight()
+ available = displayHeight - anchorView.getHeight()
- mActivity.findViewById(R.id.anchor_upper).getHeight();
maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
assertTrue(maxAvailableHeight > 0);
- assertTrue(maxAvailableHeight <= avaliable);
+ assertTrue(maxAvailableHeight <= available);
}
@UiThreadTest
@@ -815,6 +853,7 @@
mInstrumentation.waitForIdleSync();
// Do not update if it is not shown
assertFalse(mPopupWindow.isShowing());
+ assertFalse(mPopupWindow.isAttachedInDecor());
assertEquals(100, mPopupWindow.getWidth());
assertEquals(100, mPopupWindow.getHeight());
@@ -822,6 +861,14 @@
mPopupWindow.getContentView().getLocationInWindow(viewInWindowXY);
// update if it is not shown
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.update(80, 80));
+
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mPopupWindow.isShowing());
+ assertEquals(80, mPopupWindow.getWidth());
+ assertEquals(80, mPopupWindow.getHeight());
+
+ // update if it is not shown
mInstrumentation.runOnMainSync(() -> mPopupWindow.update(20, 50, 50, 50));
mInstrumentation.waitForIdleSync();
@@ -1061,6 +1108,61 @@
assertEquals(LayoutParams.MATCH_PARENT, p.height);
}
+ public void testAccessElevation() {
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.setElevation(2.0f));
+
+ showPopup();
+ assertEquals(2.0f, mPopupWindow.getElevation());
+
+ dismissPopup();
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.setElevation(4.0f));
+ showPopup();
+ assertEquals(4.0f, mPopupWindow.getElevation());
+
+ dismissPopup();
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.setElevation(10.0f));
+ showPopup();
+ assertEquals(10.0f, mPopupWindow.getElevation());
+ }
+
+ public void testAccessSoftInputMode() {
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+ mInstrumentation.runOnMainSync(
+ () -> mPopupWindow.setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE));
+
+ showPopup();
+ assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE,
+ mPopupWindow.getSoftInputMode());
+
+ dismissPopup();
+ mInstrumentation.runOnMainSync(
+ () -> mPopupWindow.setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN));
+ showPopup();
+ assertEquals(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN,
+ mPopupWindow.getSoftInputMode());
+ }
+
+ public void testAccessSplitTouchEnabled() {
+ mPopupWindow = createPopupWindow(createPopupContent(50, 50));
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.setSplitTouchEnabled(true));
+
+ showPopup();
+ assertTrue(mPopupWindow.isSplitTouchEnabled());
+
+ dismissPopup();
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.setSplitTouchEnabled(false));
+ showPopup();
+ assertFalse(mPopupWindow.isSplitTouchEnabled());
+
+ dismissPopup();
+ mInstrumentation.runOnMainSync(() -> mPopupWindow.setSplitTouchEnabled(true));
+ showPopup();
+ assertTrue(mPopupWindow.isSplitTouchEnabled());
+ }
+
private static class BaseTransition extends Transition {
@Override
public void captureStartValues(TransitionValues transitionValues) {}
diff --git a/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java b/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
new file mode 100644
index 0000000..442d5f7
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.RadioButton;
+
+/**
+ * A minimal application for {@link RadioButton} test.
+ */
+public class RadioButtonCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.radiobutton_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
index eb9387b..f98a45e 100644
--- a/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RadioButtonTest.java
@@ -16,6 +16,12 @@
package android.widget.cts;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+import android.widget.CheckBox;
import android.widget.cts.R;
@@ -24,59 +30,154 @@
import android.test.UiThreadTest;
import android.util.AttributeSet;
import android.widget.RadioButton;
+import android.widget.cts.util.ViewTestUtils;
-/**
- * Test {@link RadioButton}.
- */
-public class RadioButtonTest extends InstrumentationTestCase {
- private Context mContext;
+import static org.mockito.Mockito.*;
+
+@SmallTest
+public class RadioButtonTest extends ActivityInstrumentationTestCase2<RadioButtonCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private RadioButton mRadioButton;
+
+ public RadioButtonTest() {
+ super("android.widget.cts", RadioButtonCtsActivity.class);
+ }
@Override
protected void setUp() throws Exception {
super.setUp();
- mContext = getInstrumentation().getTargetContext();
+
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mRadioButton = (RadioButton) mActivity.findViewById(R.id.radio_button);
}
public void testConstructor() {
- AttributeSet attrs = mContext.getResources().getLayout(R.layout.radiogroup_1);
- assertNotNull(attrs);
+ new RadioButton(mActivity);
+ new RadioButton(mActivity, null);
+ new RadioButton(mActivity, null, android.R.attr.radioButtonStyle);
+ new RadioButton(mActivity, null, 0,
+ android.R.style.Widget_Material_Light_CompoundButton_RadioButton);
- new RadioButton(mContext);
try {
new RadioButton(null);
fail("The constructor should throw NullPointerException when param Context is null.");
} catch (NullPointerException e) {
}
- new RadioButton(mContext, attrs);
try {
- new RadioButton(null, attrs);
+ new RadioButton(null, null);
fail("The constructor should throw NullPointerException when param Context is null.");
} catch (NullPointerException e) {
}
- new RadioButton(mContext, null);
-
- new RadioButton(mContext, attrs, 0);
try {
- new RadioButton(null, attrs, 0);
+ new RadioButton(null, null, 0);
fail("The constructor should throw NullPointerException when param Context is null.");
} catch (NullPointerException e) {
}
- new RadioButton(mContext, null, 0);
- new RadioButton(mContext, attrs, Integer.MAX_VALUE);
- new RadioButton(mContext, attrs, Integer.MIN_VALUE);
}
- @UiThreadTest
- public void testToggle() {
- RadioButton button = new RadioButton(mContext);
- assertFalse(button.isChecked());
+ public void testText() {
+ assertTrue(TextUtils.equals(
+ mActivity.getString(R.string.hello_world), mRadioButton.getText()));
- button.toggle();
- assertTrue(button.isChecked());
+ mInstrumentation.runOnMainSync(() -> mRadioButton.setText("new text"));
+ assertTrue(TextUtils.equals("new text", mRadioButton.getText()));
- // Can't be toggled if it is checked
- button.toggle();
- assertTrue(button.isChecked());
+ mInstrumentation.runOnMainSync(() -> mRadioButton.setText(R.string.text_name));
+ assertTrue(TextUtils.equals(
+ mActivity.getString(R.string.text_name), mRadioButton.getText()));
+ }
+
+ public void testAccessChecked() {
+ final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(RadioButton.OnCheckedChangeListener.class);
+ mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mRadioButton.isChecked());
+
+ // not checked -> not checked
+ mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(false));
+ verifyZeroInteractions(mockCheckedChangeListener);
+ assertFalse(mRadioButton.isChecked());
+
+ // not checked -> checked
+ mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(true));
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+ assertTrue(mRadioButton.isChecked());
+
+ // checked -> checked
+ mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(true));
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+ assertTrue(mRadioButton.isChecked());
+
+ // checked -> not checked
+ mInstrumentation.runOnMainSync(() -> mRadioButton.setChecked(false));
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, false);
+ assertFalse(mRadioButton.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
+
+ public void testToggleViaApi() {
+ final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(RadioButton.OnCheckedChangeListener.class);
+ mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mRadioButton.isChecked());
+
+ // toggle to checked
+ mInstrumentation.runOnMainSync(() -> mRadioButton.toggle());
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+ assertTrue(mRadioButton.isChecked());
+
+ // try toggle to not checked - this should leave the radio button in checked state
+ mInstrumentation.runOnMainSync(() -> mRadioButton.toggle());
+ assertTrue(mRadioButton.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
+
+ public void testToggleViaEmulatedTap() {
+ final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(RadioButton.OnCheckedChangeListener.class);
+ mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mRadioButton.isChecked());
+
+ // tap to checked
+ ViewTestUtils.emulateTapOnViewCenter(mInstrumentation, mRadioButton);
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+ assertTrue(mRadioButton.isChecked());
+
+ // tap to not checked - this should leave the radio button in checked state
+ ViewTestUtils.emulateTapOnViewCenter(mInstrumentation, mRadioButton);
+ assertTrue(mRadioButton.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
+ }
+
+ public void testToggleViaPerformClick() {
+ final RadioButton.OnCheckedChangeListener mockCheckedChangeListener =
+ mock(RadioButton.OnCheckedChangeListener.class);
+ mRadioButton.setOnCheckedChangeListener(mockCheckedChangeListener);
+ verifyZeroInteractions(mockCheckedChangeListener);
+
+ assertFalse(mRadioButton.isChecked());
+
+ // click to checked
+ mInstrumentation.runOnMainSync(() -> mRadioButton.performClick());
+ verify(mockCheckedChangeListener, times(1)).onCheckedChanged(mRadioButton, true);
+ assertTrue(mRadioButton.isChecked());
+
+ // click to not checked - this should leave the radio button in checked state
+ mInstrumentation.runOnMainSync(() -> mRadioButton.performClick());
+ assertTrue(mRadioButton.isChecked());
+
+ verifyNoMoreInteractions(mockCheckedChangeListener);
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
index 2f3be6f..dfff694 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
@@ -16,6 +16,7 @@
package android.widget.cts;
+import android.app.Instrumentation;
import android.widget.cts.R;
import org.xmlpull.v1.XmlPullParser;
@@ -43,6 +44,7 @@
*/
public class RelativeLayoutTest extends
ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
+ private Instrumentation mInstrumentation;
private Activity mActivity;
public RelativeLayoutTest() {
@@ -52,6 +54,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+
+ mInstrumentation = getInstrumentation();
mActivity = getActivity();
}
@@ -86,27 +90,19 @@
ViewAsserts.assertRightAligned(relativeLayout, view13);
relativeLayout.setIgnoreGravity(R.id.relative_view13);
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.requestLayout();
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.requestLayout());
+ mInstrumentation.waitForIdleSync();
ViewAsserts.assertRightAligned(relativeLayout, view12);
ViewAsserts.assertLeftAligned(relativeLayout, view13);
relativeLayout.setIgnoreGravity(0);
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.requestLayout();
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.requestLayout());
+ mInstrumentation.waitForIdleSync();
ViewAsserts.assertRightAligned(relativeLayout, view12);
ViewAsserts.assertRightAligned(relativeLayout, view13);
}
- public void testSetGravity() {
+ public void testAccessGravity() {
final RelativeLayout relativeLayout = (RelativeLayout) mActivity.findViewById(
R.id.relative_sublayout_gravity);
@@ -120,48 +116,38 @@
assertEquals(view11.getTop(), view10.getBottom());
// -- BOTTOM && RIGHT
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setGravity(Gravity.BOTTOM | Gravity.RIGHT);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(
+ () -> relativeLayout.setGravity(Gravity.BOTTOM | Gravity.RIGHT));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.BOTTOM | Gravity.RIGHT, relativeLayout.getGravity());
ViewAsserts.assertRightAligned(relativeLayout, view10);
assertEquals(view11.getTop(), view10.getBottom());
ViewAsserts.assertRightAligned(relativeLayout, view11);
ViewAsserts.assertBottomAligned(relativeLayout, view11);
// -- BOTTOM
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setGravity(Gravity.BOTTOM);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.setGravity(Gravity.BOTTOM));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.BOTTOM | Gravity.START, relativeLayout.getGravity());
ViewAsserts.assertLeftAligned(relativeLayout, view10);
assertEquals(view11.getTop(), view10.getBottom());
ViewAsserts.assertLeftAligned(relativeLayout, view11);
ViewAsserts.assertBottomAligned(relativeLayout, view11);
// CENTER_HORIZONTAL
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setGravity(Gravity.CENTER_HORIZONTAL);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.setGravity(Gravity.CENTER_HORIZONTAL));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.CENTER_HORIZONTAL | Gravity.TOP,
+ relativeLayout.getGravity());
ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view10);
ViewAsserts.assertTopAligned(relativeLayout, view10);
ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view11);
assertEquals(view11.getTop(), view10.getBottom());
// CENTER_VERTICAL
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setGravity(Gravity.CENTER_VERTICAL);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.setGravity(Gravity.CENTER_VERTICAL));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.CENTER_VERTICAL | Gravity.START, relativeLayout.getGravity());
ViewAsserts.assertLeftAligned(relativeLayout, view10);
int topSpace = view10.getTop();
int bottomSpace = relativeLayout.getHeight() - view11.getBottom();
@@ -184,24 +170,20 @@
assertEquals(view11.getTop(), view10.getBottom());
// RIGHT
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setHorizontalGravity(Gravity.RIGHT);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.setHorizontalGravity(Gravity.RIGHT));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.RIGHT, Gravity.HORIZONTAL_GRAVITY_MASK & relativeLayout.getGravity());
ViewAsserts.assertRightAligned(relativeLayout, view10);
ViewAsserts.assertTopAligned(relativeLayout, view10);
ViewAsserts.assertRightAligned(relativeLayout, view11);
assertEquals(view11.getTop(), view10.getBottom());
// CENTER_HORIZONTAL
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setHorizontalGravity(Gravity.CENTER_HORIZONTAL);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(
+ () -> relativeLayout.setHorizontalGravity(Gravity.CENTER_HORIZONTAL));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.CENTER_HORIZONTAL,
+ Gravity.HORIZONTAL_GRAVITY_MASK & relativeLayout.getGravity());
ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view10);
ViewAsserts.assertTopAligned(relativeLayout, view10);
ViewAsserts.assertHorizontalCenterAligned(relativeLayout, view11);
@@ -222,24 +204,20 @@
assertEquals(view11.getTop(), view10.getBottom());
// BOTTOM
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setVerticalGravity(Gravity.BOTTOM);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> relativeLayout.setVerticalGravity(Gravity.BOTTOM));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.BOTTOM, Gravity.VERTICAL_GRAVITY_MASK & relativeLayout.getGravity());
ViewAsserts.assertLeftAligned(relativeLayout, view10);
assertEquals(view11.getTop(), view10.getBottom());
ViewAsserts.assertLeftAligned(relativeLayout, view11);
ViewAsserts.assertBottomAligned(relativeLayout, view11);
// CENTER_VERTICAL
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- relativeLayout.setVerticalGravity(Gravity.CENTER_VERTICAL);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(
+ () -> relativeLayout.setVerticalGravity(Gravity.CENTER_VERTICAL));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(Gravity.CENTER_VERTICAL,
+ Gravity.VERTICAL_GRAVITY_MASK & relativeLayout.getGravity());
ViewAsserts.assertLeftAligned(relativeLayout, view10);
int topSpace = view10.getTop();
int bottomSpace = relativeLayout.getHeight() - view11.getBottom();
@@ -352,12 +330,9 @@
* Tests to prevent regressions in baseline alignment.
*/
public void testBaselineAlignment() {
- mActivity.runOnUiThread(new Runnable() {
- public void run() {
- mActivity.setContentView(R.layout.relative_layout_baseline);
- }
- });
- getInstrumentation().waitForIdleSync();
+ mInstrumentation.runOnMainSync(
+ () -> mActivity.setContentView(R.layout.relative_layout_baseline));
+ mInstrumentation.waitForIdleSync();
View button = mActivity.findViewById(R.id.button1);
assertTrue(button.getHeight() > 0);
diff --git a/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
new file mode 100644
index 0000000..5da8a32
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchViewCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.SearchView;
+
+/**
+ * A minimal application for {@link SearchView} test.
+ */
+public class SearchViewCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.searchview_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SearchViewTest.java b/tests/tests/widget/src/android/widget/cts/SearchViewTest.java
new file mode 100644
index 0000000..4c8cd8c
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchViewTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.res.Resources;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+import android.widget.SearchView;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Test {@link SearchView}.
+ */
+@MediumTest
+public class SearchViewTest extends ActivityInstrumentationTestCase2<SearchViewCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private SearchView mSearchView;
+
+ public SearchViewTest() {
+ super("android.widget.cts", SearchViewCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
+ }
+
+ @UiThreadTest
+ public void testConstructor() {
+ new SearchView(mActivity);
+
+ new SearchView(mActivity, null);
+
+ new SearchView(mActivity, null, android.R.attr.searchViewStyle);
+
+ new SearchView(mActivity, null, 0, android.R.style.Widget_Material_Light_SearchView);
+ }
+
+ @UiThreadTest
+ public void testAttributesFromXml() {
+ SearchView searchViewWithAttributes =
+ (SearchView) mActivity.findViewById(R.id.search_view_with_defaults);
+ assertEquals(mActivity.getString(R.string.search_query_hint),
+ searchViewWithAttributes.getQueryHint());
+ assertFalse(searchViewWithAttributes.isIconfiedByDefault());
+ assertEquals(EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS | EditorInfo.TYPE_CLASS_TEXT,
+ searchViewWithAttributes.getInputType());
+ assertEquals(EditorInfo.IME_ACTION_DONE, searchViewWithAttributes.getImeOptions());
+ assertEquals(mActivity.getResources().getDimensionPixelSize(R.dimen.search_view_max_width),
+ searchViewWithAttributes.getMaxWidth());
+ }
+
+ public void testAccessIconified() {
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+ assertTrue(mSearchView.isIconified());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(false));
+ assertFalse(mSearchView.isIconified());
+ }
+
+ public void testAccessIconifiedByDefault() {
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconifiedByDefault(true));
+ assertTrue(mSearchView.isIconfiedByDefault());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconifiedByDefault(false));
+ assertFalse(mSearchView.isIconfiedByDefault());
+ }
+
+ public void testDenyIconifyingNonInconifiableView() {
+ mInstrumentation.runOnMainSync(() -> {
+ mSearchView.setIconifiedByDefault(false);
+ mSearchView.setIconified(false);
+ });
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+ mInstrumentation.waitForIdleSync();
+
+ // Since our search view is marked with iconifiedByDefault=false, call to setIconified
+ // with true us going to be ignored, as detailed in the class-level documentation of
+ // SearchView.
+ assertFalse(mSearchView.isIconified());
+ }
+
+ public void testDenyIconifyingInconifiableView() {
+ mInstrumentation.runOnMainSync(() -> {
+ mSearchView.setIconifiedByDefault(true);
+ mSearchView.setIconified(false);
+ });
+
+ final SearchView.OnCloseListener mockDenyCloseListener =
+ mock(SearchView.OnCloseListener.class);
+ when(mockDenyCloseListener.onClose()).thenReturn(Boolean.TRUE);
+ mSearchView.setOnCloseListener(mockDenyCloseListener);
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+ mInstrumentation.waitForIdleSync();
+
+ // Our mock listener is configured to return true from its onClose, thereby preventing
+ // the iconify request to be completed. Check that the listener was called and that the
+ // search view is not iconified.
+ verify(mockDenyCloseListener, times(1)).onClose();
+ assertFalse(mSearchView.isIconified());
+ }
+
+ public void testAllowIconifyingInconifiableView() {
+ mInstrumentation.runOnMainSync(() -> {
+ mSearchView.setIconifiedByDefault(true);
+ mSearchView.setIconified(false);
+ });
+
+ final SearchView.OnCloseListener mockAllowCloseListener =
+ mock(SearchView.OnCloseListener.class);
+ when(mockAllowCloseListener.onClose()).thenReturn(Boolean.FALSE);
+ mSearchView.setOnCloseListener(mockAllowCloseListener);
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(true));
+ mInstrumentation.waitForIdleSync();
+
+ // Our mock listener is configured to return false from its onClose, thereby allowing
+ // the iconify request to be completed. Check that the listener was called and that the
+ // search view is not iconified.
+ verify(mockAllowCloseListener, times(1)).onClose();
+ assertTrue(mSearchView.isIconified());
+ }
+
+ public void testAccessMaxWidth() {
+ final Resources res = mActivity.getResources();
+ final int maxWidth1 = res.getDimensionPixelSize(R.dimen.search_view_max_width);
+ final int maxWidth2 = res.getDimensionPixelSize(R.dimen.search_view_max_width2);
+
+ // Set search view to not be iconified before running max-width tests
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(false));
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setMaxWidth(maxWidth1));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(maxWidth1, mSearchView.getMaxWidth());
+ assertTrue(mSearchView.getWidth() <= maxWidth1);
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setMaxWidth(maxWidth2));
+ mInstrumentation.waitForIdleSync();
+ assertEquals(maxWidth2, mSearchView.getMaxWidth());
+ assertTrue(mSearchView.getWidth() <= maxWidth2);
+ }
+
+ public void testAccessQuery() {
+ mInstrumentation.runOnMainSync(() -> mSearchView.setIconified(false));
+
+ final SearchView.OnQueryTextListener mockQueryTextListener =
+ mock(SearchView.OnQueryTextListener.class);
+ when(mockQueryTextListener.onQueryTextSubmit(anyString())).thenReturn(Boolean.TRUE);
+ mSearchView.setOnQueryTextListener(mockQueryTextListener);
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("alpha", false));
+ assertTrue(TextUtils.equals("alpha", mSearchView.getQuery()));
+ // Since we passed false as the second parameter to setQuery, our query text listener
+ // should have been invoked only with text change
+ verify(mockQueryTextListener, times(1)).onQueryTextChange("alpha");
+ verify(mockQueryTextListener, never()).onQueryTextSubmit(anyString());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("beta", true));
+ assertTrue(TextUtils.equals("beta", mSearchView.getQuery()));
+ // Since we passed true as the second parameter to setQuery, our query text listener
+ // should have been invoked on both callbacks
+ verify(mockQueryTextListener, times(1)).onQueryTextChange("beta");
+ verify(mockQueryTextListener, times(1)).onQueryTextSubmit("beta");
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("gamma", true));
+ assertTrue(TextUtils.equals("gamma", mSearchView.getQuery()));
+ // Since we passed true as the second parameter to setQuery, our query text listener
+ // should have been invoked on both callbacks
+ verify(mockQueryTextListener, times(1)).onQueryTextChange("gamma");
+ verify(mockQueryTextListener, times(1)).onQueryTextSubmit("gamma");
+
+ verifyNoMoreInteractions(mockQueryTextListener);
+ }
+
+ public void testAccessQueryHint() {
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQueryHint("hint 1"));
+ assertTrue(TextUtils.equals("hint 1", mSearchView.getQueryHint()));
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQueryHint("hint 2"));
+ assertTrue(TextUtils.equals("hint 2", mSearchView.getQueryHint()));
+ }
+
+ public void testAccessInputType() {
+ mInstrumentation.runOnMainSync(() ->
+ mSearchView.setInputType(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_FLAG_DECIMAL
+ | InputType.TYPE_NUMBER_FLAG_SIGNED));
+ assertEquals(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_FLAG_DECIMAL
+ | InputType.TYPE_NUMBER_FLAG_SIGNED, mSearchView.getInputType());
+
+ mInstrumentation.runOnMainSync(() ->
+ mSearchView.setInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_FLAG_CAP_WORDS));
+ assertEquals(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_FLAG_CAP_WORDS, mSearchView.getInputType());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setInputType(InputType.TYPE_CLASS_PHONE));
+ assertEquals(InputType.TYPE_CLASS_PHONE, mSearchView.getInputType());
+ }
+
+ public void testAccessImeOptions() {
+ mInstrumentation.runOnMainSync(() -> mSearchView.setImeOptions(EditorInfo.IME_ACTION_GO));
+ assertEquals(EditorInfo.IME_ACTION_GO, mSearchView.getImeOptions());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setImeOptions(EditorInfo.IME_ACTION_DONE));
+ assertEquals(EditorInfo.IME_ACTION_DONE, mSearchView.getImeOptions());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setImeOptions(EditorInfo.IME_NULL));
+ assertEquals(EditorInfo.IME_NULL, mSearchView.getImeOptions());
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
new file mode 100644
index 0000000..5b8dbfc
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.PollingCheck;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.BaseColumns;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.TextUtils;
+import android.widget.CursorAdapter;
+import android.widget.SearchView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.cts.util.ViewTestUtils;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test {@link SearchView} with {@link Cursor}-backed suggestions adapter.
+ */
+@MediumTest
+public class SearchView_CursorTest extends ActivityInstrumentationTestCase2<SearchViewCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private SearchView mSearchView;
+
+ private static final String TEXT_COLUMN_NAME = "text";
+ private String[] mTextContent;
+
+ private CursorAdapter mSuggestionsAdapter;
+
+ protected class MyQueryTextListener implements SearchView.OnQueryTextListener {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ return false;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ if (mSuggestionsAdapter == null) {
+ return false;
+ }
+
+ final MatrixCursor c = new MatrixCursor(
+ new String[] { BaseColumns._ID, TEXT_COLUMN_NAME} );
+ for (int i = 0; i < mTextContent.length; i++) {
+ if (mTextContent[i].toLowerCase().startsWith(s.toLowerCase())) {
+ c.addRow(new Object[]{i, mTextContent[i]});
+ }
+ }
+ mSuggestionsAdapter.swapCursor(c);
+ return false;
+ }
+ }
+
+ protected class MySuggestionListener implements SearchView.OnSuggestionListener {
+ @Override
+ public boolean onSuggestionSelect(int position) {
+ return false;
+ }
+
+ @Override
+ public boolean onSuggestionClick(int position) {
+ if (mSuggestionsAdapter != null) {
+ final Cursor cursor = mSuggestionsAdapter.getCursor();
+ if (cursor != null) {
+ cursor.moveToPosition(position);
+ mSearchView.setQuery(cursor.getString(1), false);
+ }
+ }
+ return false;
+ }
+ }
+
+ public SearchView_CursorTest() {
+ super("android.widget.cts", SearchViewCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ mSearchView = (SearchView) mActivity.findViewById(R.id.search_view);
+
+ // Local test data for the tests
+ mTextContent = new String[] { "Akon", "Bono", "Ciara", "Dido", "Diplo" };
+
+ mInstrumentation.runOnMainSync(() -> {
+ // Use an adapter with our custom layout for each entry. The adapter "maps"
+ // the content of the text column of our cursor to the @id/text1 view in the
+ // layout.
+ mSuggestionsAdapter = new SimpleCursorAdapter(
+ mActivity,
+ R.layout.searchview_suggestion_item,
+ null,
+ new String[] { TEXT_COLUMN_NAME },
+ new int[] { android.R.id.text1 },
+ CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
+ mSearchView.setSuggestionsAdapter(mSuggestionsAdapter);
+ });
+ }
+
+ public void testSuggestionFiltering() {
+ final SearchView.OnQueryTextListener mockQueryTextListener =
+ spy(new MyQueryTextListener());
+ when(mockQueryTextListener.onQueryTextChange(anyString())).thenCallRealMethod();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mSearchView.setIconifiedByDefault(false);
+ mSearchView.setOnQueryTextListener(mockQueryTextListener);
+ mSearchView.requestFocus();
+ });
+
+ assertTrue(mSearchView.hasFocus());
+ assertEquals(mSuggestionsAdapter, mSearchView.getSuggestionsAdapter());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("Bon", false));
+ verify(mockQueryTextListener, times(1)).onQueryTextChange("Bon");
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("Di", false));
+ verify(mockQueryTextListener, times(1)).onQueryTextChange("Di");
+ }
+
+ public void testSuggestionSelection() {
+ final SearchView.OnSuggestionListener mockSuggestionListener =
+ spy(new MySuggestionListener());
+ when(mockSuggestionListener.onSuggestionClick(anyInt())).thenCallRealMethod();
+
+ final SearchView.OnQueryTextListener mockQueryTextListener =
+ spy(new MyQueryTextListener());
+ when(mockQueryTextListener.onQueryTextChange(anyString())).thenCallRealMethod();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mSearchView.setIconifiedByDefault(false);
+ mSearchView.setOnQueryTextListener(mockQueryTextListener);
+ mSearchView.setOnSuggestionListener(mockSuggestionListener);
+ mSearchView.requestFocus();
+ });
+
+ assertTrue(mSearchView.hasFocus());
+ assertEquals(mSuggestionsAdapter, mSearchView.getSuggestionsAdapter());
+
+ mInstrumentation.runOnMainSync(() -> mSearchView.setQuery("Di", false));
+ mInstrumentation.waitForIdleSync();
+ verify(mockQueryTextListener, times(1)).onQueryTextChange("Di");
+
+ // Emulate click on the first suggestion - which should be Dido
+ final int suggestionRowHeight = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.search_view_suggestion_row_height);
+ ViewTestUtils.emulateTapOnScreen(mInstrumentation, mSearchView, mSearchView.getWidth() / 2,
+ mSearchView.getHeight() + suggestionRowHeight / 2);
+
+ // At this point we expect the click on the first suggestion to have activated a sequence
+ // of events that ends up in our suggestion listener that sets the full suggestion text
+ // as the current query. Some parts of this sequence of events are asynchronous, and those
+ // are not "caught" by Instrumentation.waitForIdleSync - which is in general not a very
+ // reliable way to wait for everything to be completed. As such, we are using our own
+ // polling check mechanism to wait until the search view's query is the fully completed
+ // suggestion for Dido. This check will time out and fail after a few seconds if anything
+ // goes wrong during the processing of the emulated tap and the code never gets to our
+ // suggestion listener
+ PollingCheck.waitFor(() -> TextUtils.equals("Dido", mSearchView.getQuery()));
+
+ // Just to be sure, verify that our spy suggestion listener was called
+ verify(mockSuggestionListener, times(1)).onSuggestionClick(0);
+ verifyNoMoreInteractions(mockSuggestionListener);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
new file mode 100644
index 0000000..16fb30e
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerCtsActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Spinner;
+
+/**
+ * A minimal application for {@link Spinner} test.
+ */
+public class SpinnerCtsActivity extends Activity {
+ /**
+ * Called with the activity is first created.
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.spinner_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
index eea1e3e..d76888f 100644
--- a/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SpinnerTest.java
@@ -16,101 +16,133 @@
package android.widget.cts;
-import android.widget.cts.R;
-
-
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
-import android.content.Context;
+import android.app.Instrumentation;
+import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
+import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.ViewTestUtils;
+
+import static org.mockito.Mockito.mock;
/**
* Test {@link Spinner}.
*/
-public class SpinnerTest extends ActivityInstrumentationTestCase2<RelativeLayoutCtsActivity> {
- private Context mTargetContext;
+@MediumTest
+public class SpinnerTest extends ActivityInstrumentationTestCase2<SpinnerCtsActivity> {
+ private Activity mActivity;
+ private Spinner mSpinnerDialogMode;
+ private Spinner mSpinnerDropdownMode;
public SpinnerTest() {
- super("android.widget.cts", RelativeLayoutCtsActivity.class);
+ super("android.widget.cts", SpinnerCtsActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
- mTargetContext = getInstrumentation().getTargetContext();
+
+ mActivity = getActivity();
+ mSpinnerDialogMode = (Spinner) mActivity.findViewById(R.id.spinner_dialog_mode);
+ mSpinnerDropdownMode = (Spinner) mActivity.findViewById(R.id.spinner_dropdown_mode);
}
- @UiThreadTest
public void testConstructor() {
- new Spinner(mTargetContext);
+ new Spinner(mActivity);
- new Spinner(mTargetContext, null);
+ new Spinner(mActivity, null);
- new Spinner(mTargetContext, null, android.R.attr.spinnerStyle);
+ new Spinner(mActivity, null, android.R.attr.spinnerStyle);
- new Spinner(mTargetContext, Spinner.MODE_DIALOG);
+ new Spinner(mActivity, Spinner.MODE_DIALOG);
- new Spinner(mTargetContext, null, android.R.attr.spinnerStyle,
+ new Spinner(mActivity, Spinner.MODE_DROPDOWN);
+
+ new Spinner(mActivity, null, android.R.attr.spinnerStyle, Spinner.MODE_DIALOG);
+
+ new Spinner(mActivity, null, android.R.attr.spinnerStyle, Spinner.MODE_DROPDOWN);
+
+ new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Light_Spinner,
Spinner.MODE_DIALOG);
- new Spinner(mTargetContext, null, android.R.attr.spinnerStyle, 0,
- Spinner.MODE_DIALOG);
+ new Spinner(mActivity, null, 0, android.R.style.Widget_Material_Light_Spinner,
+ Spinner.MODE_DROPDOWN);
- new Spinner(mTargetContext, null, android.R.attr.spinnerStyle, 0,
- Spinner.MODE_DIALOG, mTargetContext.getTheme());
+ final Resources.Theme popupTheme = mActivity.getResources().newTheme();
+ popupTheme.applyStyle(android.R.style.Theme_Material, true);
- Spinner spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
- assertEquals(mTargetContext.getString(R.string.text_view_hello), spinner.getPrompt());
+ new Spinner(mActivity, null, android.R.attr.spinnerStyle, 0, Spinner.MODE_DIALOG,
+ popupTheme);
+
+ new Spinner(mActivity, null, android.R.attr.spinnerStyle, 0, Spinner.MODE_DROPDOWN,
+ popupTheme);
}
- @UiThreadTest
- public void testGetBaseline() {
- Spinner spinner = new Spinner(mTargetContext);
-
+ private void verifyGetBaseline(Spinner spinner) {
assertEquals(-1, spinner.getBaseline());
- spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
- ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mTargetContext,
- android.widget.cts.R.array.string, android.R.layout.simple_spinner_item);
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+ R.array.string, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(adapter);
- assertTrue(spinner.getBaseline() > 0);
+ getInstrumentation().runOnMainSync(() -> {
+ spinner.setAdapter(adapter);
+ assertTrue(spinner.getBaseline() > 0);
+ });
}
- @UiThreadTest
- public void testSetOnItemClickListener() {
- Spinner spinner = new Spinner(mTargetContext);
+ public void testGetBaseline() {
+ verifyGetBaseline(mSpinnerDialogMode);
+ verifyGetBaseline(mSpinnerDropdownMode);
+ }
+ private void verifySetOnItemClickListener(Spinner spinner) {
try {
spinner.setOnItemClickListener(null);
fail("Should throw RuntimeException");
} catch (RuntimeException e) {
}
+
+ try {
+ spinner.setOnItemClickListener(mock(Spinner.OnItemClickListener.class));
+ fail("Should throw RuntimeException");
+ } catch (RuntimeException e) {
+ }
}
- @UiThreadTest
+ public void testSetOnItemClickListener() {
+ verifySetOnItemClickListener(mSpinnerDialogMode);
+ verifySetOnItemClickListener(mSpinnerDropdownMode);
+ }
+
+ private void verifyPerformClick(Spinner spinner) {
+ getInstrumentation().runOnMainSync(() -> assertTrue(spinner.performClick()));
+ }
+
public void testPerformClick() {
- final Spinner spinner = (Spinner) getActivity().findViewById(R.id.spinner1);
-
- assertTrue(spinner.performClick());
-
- // TODO: no description for the expected result for this method in its javadoc, issue?
- // Or do UI check?
+ verifyPerformClick(mSpinnerDialogMode);
+ verifyPerformClick(mSpinnerDropdownMode);
}
- @UiThreadTest
- public void testOnClick() {
- Spinner spinner = new Spinner(mTargetContext);
+ private void verifyOnClick(Spinner spinner) {
// normal value
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
AlertDialog alertDialog = builder.show();
assertTrue(alertDialog.isShowing());
+
spinner.onClick(alertDialog, 10);
assertEquals(10, spinner.getSelectedItemPosition());
assertFalse(alertDialog.isShowing());
@@ -125,32 +157,42 @@
Dialog dialog = new Dialog(getActivity());
dialog.show();
assertTrue(dialog.isShowing());
+
spinner.onClick(dialog, -10);
assertEquals(-10, spinner.getSelectedItemPosition());
assertFalse(dialog.isShowing());
}
@UiThreadTest
- public void testAccessPrompt() {
+ public void testOnClick() {
+ verifyOnClick(mSpinnerDialogMode);
+ verifyOnClick(mSpinnerDropdownMode);
+ }
+
+ private void verifyAccessPrompt(Spinner spinner) {
+ final String initialPrompt = mActivity.getString(R.string.text_view_hello);
+ assertEquals(initialPrompt, spinner.getPrompt());
+
+ final Instrumentation instrumentation = getInstrumentation();
final String promptText = "prompt text";
- Spinner spinner = new Spinner(mTargetContext);
-
- spinner.setPrompt(promptText);
+ instrumentation.runOnMainSync(() -> spinner.setPrompt(promptText));
assertEquals(promptText, spinner.getPrompt());
spinner.setPrompt(null);
assertNull(spinner.getPrompt());
-
- // TODO: find the dialog and get its title to assert whether setPrompt() takes effect?
}
- @UiThreadTest
- public void testSetPromptId() {
- Spinner spinner = new Spinner(mTargetContext);
+ public void testAccessPrompt() {
+ verifyAccessPrompt(mSpinnerDialogMode);
+ verifyAccessPrompt(mSpinnerDropdownMode);
+ }
- spinner.setPromptId(R.string.hello_world);
- assertEquals(mTargetContext.getString(R.string.hello_world), spinner.getPrompt());
+ private void verifySetPromptId(Spinner spinner) {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ instrumentation.runOnMainSync(() -> spinner.setPromptId(R.string.hello_world));
+ assertEquals(mActivity.getString(R.string.hello_world), spinner.getPrompt());
try {
spinner.setPromptId(-1);
@@ -165,23 +207,209 @@
} catch (NotFoundException e) {
// issue 1695243, not clear what is supposed to happen if promptId is exceptional.
}
+ }
- // TODO: find the dialog and get its title to assert whether setPromptId() takes effect?
+ public void testSetPromptId() {
+ verifySetPromptId(mSpinnerDialogMode);
+ verifySetPromptId(mSpinnerDropdownMode);
}
@UiThreadTest
public void testGetPopupContext() {
- Theme theme = mTargetContext.getResources().newTheme();
- Spinner themeSpinner = new Spinner(mTargetContext, null,
+ Theme theme = mActivity.getResources().newTheme();
+ Spinner themeSpinner = new Spinner(mActivity, null,
android.R.attr.spinnerStyle, 0, Spinner.MODE_DIALOG, theme);
- assertNotSame(mTargetContext, themeSpinner.getPopupContext());
+ assertNotSame(mActivity, themeSpinner.getPopupContext());
assertSame(theme, themeSpinner.getPopupContext().getTheme());
ContextThemeWrapper context = (ContextThemeWrapper)themeSpinner.getPopupContext();
- assertSame(mTargetContext, context.getBaseContext());
+ assertSame(mActivity, context.getBaseContext());
}
- public void testOnLayout() {
- // onLayout() is implementation details, do NOT test
+ private void verifyGravity(Spinner spinner) {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // Note that here we're using a custom layout for the spinner's selected item
+ // that doesn't span the whole width of the parent. That way we're exercising the
+ // relevant path in spinner's layout pass that handles the currently set gravity
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+ R.array.string, R.layout.simple_spinner_item_layout);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ instrumentation.runOnMainSync(() -> spinner.setAdapter(adapter));
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, spinner, () -> {
+ spinner.setSelection(1);
+ spinner.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
+ spinner.requestLayout();
+ });
+
+ instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.LEFT));
+ assertEquals(Gravity.LEFT, spinner.getGravity());
+
+ instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.CENTER_HORIZONTAL));
+ assertEquals(Gravity.CENTER_HORIZONTAL, spinner.getGravity());
+
+ instrumentation.runOnMainSync((() -> spinner.setGravity(Gravity.RIGHT)));
+ assertEquals(Gravity.RIGHT, spinner.getGravity());
+
+ instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.START));
+ assertEquals(Gravity.START, spinner.getGravity());
+
+ instrumentation.runOnMainSync(() -> spinner.setGravity(Gravity.END));
+ assertEquals(Gravity.END, spinner.getGravity());
+ }
+
+ public void testGravity() {
+ verifyGravity(mSpinnerDialogMode);
+ verifyGravity(mSpinnerDropdownMode);
+ }
+
+ public void testDropDownMetricsDropdownMode() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+ R.array.string, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ instrumentation.runOnMainSync(() -> mSpinnerDropdownMode.setAdapter(adapter));
+
+ final Resources res = mActivity.getResources();
+ final int dropDownWidth = res.getDimensionPixelSize(R.dimen.spinner_dropdown_width);
+ final int dropDownOffsetHorizontal =
+ res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_h);
+ final int dropDownOffsetVertical =
+ res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_v);
+
+ instrumentation.runOnMainSync(() -> {
+ mSpinnerDropdownMode.setDropDownWidth(dropDownWidth);
+ mSpinnerDropdownMode.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
+ mSpinnerDropdownMode.setDropDownVerticalOffset(dropDownOffsetVertical);
+ });
+
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ ViewTestUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDropdownMode);
+ // Verify that we're showing the popup
+ assertTrue(mSpinnerDropdownMode.isPopupShowing());
+
+ // And test its attributes
+ assertEquals(dropDownWidth, mSpinnerDropdownMode.getDropDownWidth());
+ // TODO: restore when b/28089349 is addressed
+ // assertEquals(dropDownOffsetHorizontal,
+ // mSpinnerDropdownMode.getDropDownHorizontalOffset());
+ assertEquals(dropDownOffsetVertical, mSpinnerDropdownMode.getDropDownVerticalOffset());
+ }
+
+ public void testDropDownMetricsDialogMode() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+ R.array.string, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ instrumentation.runOnMainSync(() -> mSpinnerDialogMode.setAdapter(adapter));
+
+ final Resources res = mActivity.getResources();
+ final int dropDownWidth = res.getDimensionPixelSize(R.dimen.spinner_dropdown_width);
+ final int dropDownOffsetHorizontal =
+ res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_h);
+ final int dropDownOffsetVertical =
+ res.getDimensionPixelSize(R.dimen.spinner_dropdown_offset_v);
+
+ instrumentation.runOnMainSync(() -> {
+ // These are all expected to be no-ops
+ mSpinnerDialogMode.setDropDownWidth(dropDownWidth);
+ mSpinnerDialogMode.setDropDownHorizontalOffset(dropDownOffsetHorizontal);
+ mSpinnerDialogMode.setDropDownVerticalOffset(dropDownOffsetVertical);
+ });
+
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ ViewTestUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDialogMode);
+ // Verify that we're showing the popup
+ assertTrue(mSpinnerDialogMode.isPopupShowing());
+
+ // And test its attributes. Note that we are not testing the result of getDropDownWidth
+ // for this mode
+ assertEquals(0, mSpinnerDialogMode.getDropDownHorizontalOffset());
+ assertEquals(0, mSpinnerDialogMode.getDropDownVerticalOffset());
+ }
+
+ public void testDropDownBackgroundDropdownMode() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+ R.array.string, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ instrumentation.runOnMainSync(() -> mSpinnerDropdownMode.setAdapter(adapter));
+
+ // Set blue background on the popup
+ instrumentation.runOnMainSync(() ->
+ mSpinnerDropdownMode.setPopupBackgroundResource(R.drawable.blue_fill));
+
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ ViewTestUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDropdownMode);
+ // Verify that we're showing the popup
+ assertTrue(mSpinnerDropdownMode.isPopupShowing());
+ // And test its fill
+ Drawable dropDownBackground = mSpinnerDropdownMode.getPopupBackground();
+ TestUtils.assertAllPixelsOfColor("Drop down should be blue", dropDownBackground,
+ dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+ false, Color.BLUE, 1, true);
+
+ // Dismiss the popup with the emulated back key
+ instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ instrumentation.waitForIdleSync();
+ // Verify that we're not showing the popup
+ assertFalse(mSpinnerDropdownMode.isPopupShowing());
+
+ // Set yellow background on the popup
+ instrumentation.runOnMainSync(() ->
+ mSpinnerDropdownMode.setPopupBackgroundDrawable(
+ mActivity.getDrawable(R.drawable.yellow_fill)));
+
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ ViewTestUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDropdownMode);
+ // Verify that we're showing the popup
+ assertTrue(mSpinnerDropdownMode.isPopupShowing());
+ // And test its fill
+ dropDownBackground = mSpinnerDropdownMode.getPopupBackground();
+ TestUtils.assertAllPixelsOfColor("Drop down should be yellow", dropDownBackground,
+ dropDownBackground.getBounds().width(), dropDownBackground.getBounds().height(),
+ false, Color.YELLOW, 1, true);
+ }
+
+ public void testDropDownBackgroundDialogMode() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(mActivity,
+ R.array.string, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ instrumentation.runOnMainSync(() -> mSpinnerDialogMode.setAdapter(adapter));
+
+ // Set blue background on the popup
+ instrumentation.runOnMainSync(() ->
+ mSpinnerDialogMode.setPopupBackgroundResource(R.drawable.blue_fill));
+
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ ViewTestUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDialogMode);
+ // Verify that we're showing the popup
+ assertTrue(mSpinnerDialogMode.isPopupShowing());
+ // And test that getPopupBackground returns null
+ assertNull(mSpinnerDialogMode.getPopupBackground());
+
+ // Dismiss the popup with the emulated back key
+ instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+ instrumentation.waitForIdleSync();
+ // Verify that we're not showing the popup
+ assertFalse(mSpinnerDialogMode.isPopupShowing());
+
+ // Set yellow background on the popup
+ instrumentation.runOnMainSync(() ->
+ mSpinnerDialogMode.setPopupBackgroundDrawable(
+ mActivity.getDrawable(R.drawable.yellow_fill)));
+
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ ViewTestUtils.emulateTapOnViewCenter(instrumentation, mSpinnerDialogMode);
+ // Verify that we're showing the popup
+ assertTrue(mSpinnerDialogMode.isPopupShowing());
+ // And test that getPopupBackground returns null
+ assertNull(mSpinnerDialogMode.getPopupBackground());
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchTest.java b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
index 216b17b..ef33015 100644
--- a/tests/tests/widget/src/android/widget/cts/SwitchTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
@@ -17,22 +17,28 @@
package android.widget.cts;
import android.app.Activity;
+import android.app.Instrumentation;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.SmallTest;
+import android.view.ContextThemeWrapper;
+import android.view.ViewGroup;
import android.widget.Switch;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
+import android.widget.cts.util.TestUtils;
+import android.widget.cts.util.ViewTestUtils;
/**
* Test {@link Switch}.
*/
@SmallTest
-public class SwitchTest extends ActivityInstrumentationTestCase<SwitchCtsActivity> {
+public class SwitchTest extends ActivityInstrumentationTestCase2<SwitchCtsActivity> {
private Activity mActivity;
private Switch mSwitch;
@@ -44,7 +50,10 @@
protected void setUp() throws Exception {
super.setUp();
mActivity = getActivity();
- mSwitch = (Switch) mActivity.findViewById(R.id.switch_view);
+ }
+
+ private Switch findSwitchById(int id) {
+ return (Switch) mActivity.findViewById(id);
}
@UiThreadTest
@@ -60,6 +69,9 @@
@UiThreadTest
public void testAccessThumbTint() {
+ mSwitch = findSwitchById(R.id.switch1);
+
+ // These are the default set in layout XML
assertEquals(Color.WHITE, mSwitch.getThumbTintList().getDefaultColor());
assertEquals(Mode.SRC_OVER, mSwitch.getThumbTintMode());
@@ -73,6 +85,9 @@
@UiThreadTest
public void testAccessTrackTint() {
+ mSwitch = findSwitchById(R.id.switch1);
+
+ // These are the default set in layout XML
assertEquals(Color.BLACK, mSwitch.getTrackTintList().getDefaultColor());
assertEquals(Mode.SRC_ATOP, mSwitch.getTrackTintMode());
@@ -83,4 +98,175 @@
assertSame(colors, mSwitch.getTrackTintList());
assertEquals(Mode.XOR, mSwitch.getTrackTintMode());
}
+
+ public void testAccessThumbDrawable() {
+ mSwitch = findSwitchById(R.id.switch2);
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // This is the default set in layout XML
+ Drawable thumbDrawable = mSwitch.getThumbDrawable();
+ TestUtils.assertAllPixelsOfColor("Thumb drawable should be blue", thumbDrawable,
+ thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+ Color.BLUE, 1, true);
+
+ // Change thumb drawable to red
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setThumbDrawable(mActivity.getDrawable(R.drawable.icon_red)));
+ thumbDrawable = mSwitch.getThumbDrawable();
+ TestUtils.assertAllPixelsOfColor("Thumb drawable should be red", thumbDrawable,
+ thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+ Color.RED, 1, true);
+
+ // Change thumb drawable to green
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setThumbResource(R.drawable.icon_green));
+ thumbDrawable = mSwitch.getThumbDrawable();
+ TestUtils.assertAllPixelsOfColor("Thumb drawable should be green", thumbDrawable,
+ thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+ Color.GREEN, 1, true);
+
+ // Now tint the latest (green) thumb drawable with 50% blue SRC_OVER
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch, () -> {
+ mSwitch.setThumbTintList(ColorStateList.valueOf(0x800000FF));
+ mSwitch.setThumbTintMode(Mode.SRC_OVER);
+ });
+ thumbDrawable = mSwitch.getThumbDrawable();
+ TestUtils.assertAllPixelsOfColor("Thumb drawable should be green / blue", thumbDrawable,
+ thumbDrawable.getIntrinsicWidth(), thumbDrawable.getIntrinsicHeight(), false,
+ TestUtils.compositeColors(0x800000FF, Color.GREEN), 1, true);
+ }
+
+ public void testAccessTrackDrawable() {
+ mSwitch = findSwitchById(R.id.switch2);
+ final Instrumentation instrumentation = getInstrumentation();
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setTrackTintMode(Mode.DST));
+
+ // This is the default set in layout XML
+ Drawable trackDrawable = mSwitch.getTrackDrawable();
+ Rect trackDrawableBounds = trackDrawable.getBounds();
+ TestUtils.assertAllPixelsOfColor("Track drawable should be 50% red", trackDrawable,
+ trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+ 0x80FF0000, 1, true);
+
+ // Change track drawable to blue
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setTrackDrawable(mActivity.getDrawable(R.drawable.blue_fill)));
+ trackDrawable = mSwitch.getTrackDrawable();
+ trackDrawableBounds = trackDrawable.getBounds();
+ TestUtils.assertAllPixelsOfColor("Track drawable should be blue", trackDrawable,
+ trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+ Color.BLUE, 1, true);
+
+ // Change track drawable to green
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setTrackResource(R.drawable.green_fill));
+ trackDrawable = mSwitch.getTrackDrawable();
+ trackDrawableBounds = trackDrawable.getBounds();
+ TestUtils.assertAllPixelsOfColor("Track drawable should be green", trackDrawable,
+ trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+ Color.GREEN, 1, true);
+
+ // Now tint the latest (green) track drawable with 50% blue SRC_OVER
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch, () -> {
+ mSwitch.setTrackTintList(ColorStateList.valueOf(0x800000FF));
+ mSwitch.setTrackTintMode(Mode.SRC_OVER);
+ });
+ trackDrawable = mSwitch.getTrackDrawable();
+ trackDrawableBounds = trackDrawable.getBounds();
+ TestUtils.assertAllPixelsOfColor("Track drawable should be green / blue", trackDrawable,
+ trackDrawableBounds.width(), trackDrawableBounds.height(), false,
+ TestUtils.compositeColors(0x800000FF, Color.GREEN), 1, true);
+ }
+
+ public void testAccessText() {
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // Run text-related tests on a Holo-themed switch, since under Material themes we
+ // are not showing texts by default.
+ mSwitch = new Switch(new ContextThemeWrapper(mActivity, android.R.style.Theme_Holo_Light));
+ instrumentation.runOnMainSync(
+ () -> ((ViewGroup) mActivity.findViewById(R.id.container)).addView(mSwitch));
+
+ // Set "on" text and verify it
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setTextOn("Text on"));
+ assertEquals("Text on", mSwitch.getTextOn());
+
+ // Set "off" text and verify it
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setTextOff("Text off"));
+ assertEquals("Text off", mSwitch.getTextOff());
+
+ // Turn text display on
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setShowText(true));
+ assertTrue(mSwitch.getShowText());
+
+ // Use custom text appearance. Since we don't have APIs to query this facet of Switch,
+ // just test that it's not crashing.
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSwitchTextAppearance(mActivity, R.style.TextAppearance_WithColor));
+
+ // Use custom typeface. Since we don't have APIs to query this facet of Switch,
+ // just test that it's not crashing.
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSwitchTypeface(Typeface.MONOSPACE));
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSwitchTypeface(Typeface.SERIF, Typeface.ITALIC));
+
+ // Set and verify padding between the thumb and the text
+ final int thumbTextPadding = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.switch_thumb_text_padding);
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setThumbTextPadding(thumbTextPadding));
+ assertEquals(thumbTextPadding, mSwitch.getThumbTextPadding());
+
+ // Set and verify padding between the switch and the text
+ final int switchPadding = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.switch_padding);
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSwitchPadding(switchPadding));
+ assertEquals(switchPadding, mSwitch.getSwitchPadding());
+
+ // Turn text display off
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setShowText(false));
+ assertFalse(mSwitch.getShowText());
+ }
+
+ public void testAccessMinWidth() {
+ mSwitch = findSwitchById(R.id.switch3);
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // Set custom min width on the switch and verify that it's at least that wide
+ final int switchMinWidth = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.switch_min_width);
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSwitchMinWidth(switchMinWidth));
+ assertEquals(switchMinWidth, mSwitch.getSwitchMinWidth());
+ assertTrue(mSwitch.getWidth() >= switchMinWidth);
+
+ // And set another (larger) min width
+ final int switchMinWidth2 = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.switch_min_width2);
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSwitchMinWidth(switchMinWidth2));
+ assertEquals(switchMinWidth2, mSwitch.getSwitchMinWidth());
+ assertTrue(mSwitch.getWidth() >= switchMinWidth2);
+ }
+
+ public void testAccessSplitTrack() {
+ mSwitch = findSwitchById(R.id.switch3);
+ final Instrumentation instrumentation = getInstrumentation();
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSplitTrack(true));
+ assertTrue(mSwitch.getSplitTrack());
+
+ ViewTestUtils.runOnMainAndDrawSync(instrumentation, mSwitch,
+ () -> mSwitch.setSplitTrack(false));
+ assertFalse(mSwitch.getSplitTrack());
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 4a709dd..437b4da 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -2672,6 +2672,54 @@
}
}
+ public void testTextViewInWeigthenedLayoutChangesWidthAfterSetText() {
+ final TextView textView = new TextView(getActivity());
+ textView.setEllipsize(TruncateAt.END);
+ textView.setSingleLine(true);
+ textView.setText("a");
+
+ TextView otherTextView = new TextView(getActivity());
+ otherTextView.setSingleLine(true);
+ otherTextView.setText("any");
+
+ final LinearLayout layout = new LinearLayout(mActivity);
+ layout.setOrientation(LinearLayout.HORIZONTAL);
+
+ // TextView under test has weight 1, and width 0
+ layout.addView(textView, new LinearLayout.LayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
+
+ // other TextView has default weight
+ layout.addView(otherTextView, new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ // main layout params
+ layout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().setContentView(layout);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ int oldWidth = textView.getWidth();
+
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textView.setText("aaa");
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue("TextView should have larger width after a longer text is set",
+ textView.getWidth() > oldWidth);
+ }
+
public void testSetCursorVisible() {
mTextView = new TextView(mActivity);
diff --git a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
index 7f9690c..872e68c 100644
--- a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
@@ -17,8 +17,6 @@
package android.widget.cts;
import android.app.Instrumentation;
-import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.test.ActivityInstrumentationTestCase2;
@@ -27,7 +25,6 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.widget.ListPopupWindow;
import android.widget.Toolbar;
import android.widget.cts.util.TestUtils;
import android.widget.cts.util.ViewTestUtils;
@@ -36,8 +33,9 @@
@MediumTest
public class ToolbarTest extends ActivityInstrumentationTestCase2<ToolbarCtsActivity> {
- private Toolbar mMainToolbar;
+ private Instrumentation mInstrumentation;
private ToolbarCtsActivity mActivity;
+ private Toolbar mMainToolbar;
public ToolbarTest() {
super("android.widget.cts", ToolbarCtsActivity.class);
@@ -46,6 +44,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+
+ mInstrumentation = getInstrumentation();
mActivity = getActivity();
mMainToolbar = mActivity.getMainToolbar();
}
@@ -67,45 +67,41 @@
// of getTitle / getSubtitle, this logic follows the path of deferred layout
// and invalidation of the TextViews that show the title / subtitle in the Toolbar.
- final Instrumentation instrumentation = getInstrumentation();
-
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setTitle(R.string.toolbar_title));
assertEquals(mActivity.getString(R.string.toolbar_title), mMainToolbar.getTitle());
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setTitle("New title"));
assertEquals("New title", mMainToolbar.getTitle());
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
assertEquals(mActivity.getString(R.string.toolbar_subtitle), mMainToolbar.getSubtitle());
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setSubtitle("New subtitle"));
assertEquals("New subtitle", mMainToolbar.getSubtitle());
}
public void testTitleAndSubtitleAppearance() {
- final Instrumentation instrumentation = getInstrumentation();
-
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setTitle(R.string.toolbar_title));
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
// Since there are no APIs to get reference to the underlying implementation of
// title and subtitle, here we are testing that calling the relevant APIs doesn't crash
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setTitleTextColor(Color.RED));
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setSubtitleTextColor(Color.BLUE));
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setTitleTextAppearance(
mActivity, R.style.TextAppearance_NotColors));
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setSubtitleTextAppearance(
mActivity, R.style.TextAppearance_WithColor));
}
@@ -139,9 +135,7 @@
}
public void testMenuContent() {
- final Instrumentation instrumentation = getInstrumentation();
-
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
final Menu menu = mMainToolbar.getMenu();
@@ -170,34 +164,30 @@
}
public void testMenuOverflowShowHide() {
- final Instrumentation instrumentation = getInstrumentation();
-
// Inflate menu and check that we're not showing overflow menu yet
- instrumentation.runOnMainSync(() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
assertFalse(mMainToolbar.isOverflowMenuShowing());
// Ask to show overflow menu and check that it's showing
- instrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
+ mInstrumentation.waitForIdleSync();
assertTrue(mMainToolbar.isOverflowMenuShowing());
// Ask to hide the overflow menu and check that it's not showing
- instrumentation.runOnMainSync(() -> mMainToolbar.hideOverflowMenu());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.hideOverflowMenu());
+ mInstrumentation.waitForIdleSync();
assertFalse(mMainToolbar.isOverflowMenuShowing());
}
public void testMenuOverflowSubmenu() {
- final Instrumentation instrumentation = getInstrumentation();
-
// Inflate menu and check that we're not showing overflow menu yet
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
assertFalse(mMainToolbar.isOverflowMenuShowing());
// Ask to show overflow menu and check that it's showing
- instrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.showOverflowMenu());
+ mInstrumentation.waitForIdleSync();
assertTrue(mMainToolbar.isOverflowMenuShowing());
// Register a mock menu item click listener on the toolbar
@@ -209,162 +199,256 @@
// Ask to "perform" the share action and check that the menu click listener has
// been notified
- instrumentation.runOnMainSync(() -> menu.performIdentifierAction(R.id.action_share, 0));
+ mInstrumentation.runOnMainSync(() -> menu.performIdentifierAction(R.id.action_share, 0));
verify(menuItemClickListener, times(1)).onMenuItemClick(
menu.findItem(R.id.action_share));
// Ask to dismiss all the popups and check that we're not showing the overflow menu
- instrumentation.runOnMainSync(() -> mMainToolbar.dismissPopupMenus());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.dismissPopupMenus());
+ mInstrumentation.waitForIdleSync();
assertFalse(mMainToolbar.isOverflowMenuShowing());
}
public void testMenuOverflowIcon() {
- final Instrumentation instrumentation = getInstrumentation();
-
// Inflate menu and check that we're not showing overflow menu yet
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
final Drawable overflowIcon = mActivity.getDrawable(R.drawable.icon_red);
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setOverflowIcon(overflowIcon));
final Drawable toolbarOverflowIcon = mMainToolbar.getOverflowIcon();
TestUtils.assertAllPixelsOfColor("Overflow icon is red", toolbarOverflowIcon,
toolbarOverflowIcon.getIntrinsicWidth(), toolbarOverflowIcon.getIntrinsicHeight(),
- true, 0XFFFF0000, 1, false);
+ true, Color.RED, 1, false);
}
public void testActionView() {
- final Instrumentation instrumentation = getInstrumentation();
-
// Inflate menu and check that we don't have an expanded action view
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.inflateMenu(R.menu.toolbar_menu_search));
assertFalse(mMainToolbar.hasExpandedActionView());
// Expand search menu item's action view and verify that main toolbar has an expanded
// action view
final MenuItem searchMenuItem = mMainToolbar.getMenu().findItem(R.id.action_search);
- instrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
+ mInstrumentation.waitForIdleSync();
assertTrue(searchMenuItem.isActionViewExpanded());
assertTrue(mMainToolbar.hasExpandedActionView());
// Collapse search menu item's action view and verify that main toolbar doesn't have an
// expanded action view
- instrumentation.runOnMainSync(() -> searchMenuItem.collapseActionView());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> searchMenuItem.collapseActionView());
+ mInstrumentation.waitForIdleSync();
assertFalse(searchMenuItem.isActionViewExpanded());
assertFalse(mMainToolbar.hasExpandedActionView());
// Expand search menu item's action view again
- instrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> searchMenuItem.expandActionView());
+ mInstrumentation.waitForIdleSync();
assertTrue(searchMenuItem.isActionViewExpanded());
assertTrue(mMainToolbar.hasExpandedActionView());
// Now collapse search menu item's action view via toolbar's API and verify that main
// toolbar doesn't have an expanded action view
- instrumentation.runOnMainSync(() -> mMainToolbar.collapseActionView());
- instrumentation.waitForIdleSync();
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.collapseActionView());
+ mInstrumentation.waitForIdleSync();
assertFalse(searchMenuItem.isActionViewExpanded());
assertFalse(mMainToolbar.hasExpandedActionView());
}
public void testNavigationConfiguration() {
- final Instrumentation instrumentation = getInstrumentation();
-
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setNavigationIcon(R.drawable.icon_green));
Drawable toolbarNavigationIcon = mMainToolbar.getNavigationIcon();
TestUtils.assertAllPixelsOfColor("Navigation icon is green", toolbarNavigationIcon,
toolbarNavigationIcon.getIntrinsicWidth(),
toolbarNavigationIcon.getIntrinsicHeight(),
- true, 0xFF00FF00, 1, false);
+ true, Color.GREEN, 1, false);
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setNavigationIcon(mActivity.getDrawable(R.drawable.icon_blue)));
toolbarNavigationIcon = mMainToolbar.getNavigationIcon();
TestUtils.assertAllPixelsOfColor("Navigation icon is blue", toolbarNavigationIcon,
toolbarNavigationIcon.getIntrinsicWidth(),
toolbarNavigationIcon.getIntrinsicHeight(),
- true, 0xFF0000FF, 1, false);
+ true, Color.BLUE, 1, false);
- instrumentation.runOnMainSync(
+ mInstrumentation.runOnMainSync(
() -> mMainToolbar.setNavigationContentDescription(R.string.toolbar_navigation));
assertEquals(mActivity.getResources().getString(R.string.toolbar_navigation),
mMainToolbar.getNavigationContentDescription());
- instrumentation.runOnMainSync(
+ mInstrumentation.runOnMainSync(
() -> mMainToolbar.setNavigationContentDescription("Navigation legend"));
assertEquals("Navigation legend", mMainToolbar.getNavigationContentDescription());
}
public void testLogoConfiguration() {
- final Instrumentation instrumentation = getInstrumentation();
-
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setLogo(R.drawable.icon_yellow));
Drawable toolbarLogo = mMainToolbar.getLogo();
TestUtils.assertAllPixelsOfColor("Logo is yellow", toolbarLogo,
toolbarLogo.getIntrinsicWidth(),
toolbarLogo.getIntrinsicHeight(),
- true, 0xFFFFFF00, 1, false);
+ true, Color.YELLOW, 1, false);
- ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
() -> mMainToolbar.setLogo(mActivity.getDrawable(R.drawable.icon_red)));
toolbarLogo = mMainToolbar.getLogo();
TestUtils.assertAllPixelsOfColor("Logo is red", toolbarLogo,
toolbarLogo.getIntrinsicWidth(),
toolbarLogo.getIntrinsicHeight(),
- true, 0xFFFF0000, 1, false);
+ true, Color.RED, 1, false);
- instrumentation.runOnMainSync(
+ mInstrumentation.runOnMainSync(
() -> mMainToolbar.setLogoDescription(R.string.toolbar_logo));
assertEquals(mActivity.getResources().getString(R.string.toolbar_logo),
mMainToolbar.getLogoDescription());
- instrumentation.runOnMainSync(
+ mInstrumentation.runOnMainSync(
() -> mMainToolbar.setLogoDescription("Logo legend"));
assertEquals("Logo legend", mMainToolbar.getLogoDescription());
}
- @UiThreadTest
public void testContentInsetsLtr() {
- mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+ mInstrumentation.runOnMainSync(
+ () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
- mMainToolbar.setContentInsetsAbsolute(20, 25);
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsAbsolute(20, 25));
assertEquals(20, mMainToolbar.getContentInsetLeft());
assertEquals(20, mMainToolbar.getContentInsetStart());
assertEquals(25, mMainToolbar.getContentInsetRight());
assertEquals(25, mMainToolbar.getContentInsetEnd());
- mMainToolbar.setContentInsetsRelative(40, 20);
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(40, 20));
assertEquals(40, mMainToolbar.getContentInsetLeft());
assertEquals(40, mMainToolbar.getContentInsetStart());
assertEquals(20, mMainToolbar.getContentInsetRight());
assertEquals(20, mMainToolbar.getContentInsetEnd());
}
- @UiThreadTest
public void testContentInsetsRtl() {
- mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+ mInstrumentation.runOnMainSync(
+ () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
- mMainToolbar.setContentInsetsAbsolute(20, 25);
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsAbsolute(20, 25));
assertEquals(20, mMainToolbar.getContentInsetLeft());
assertEquals(25, mMainToolbar.getContentInsetStart());
assertEquals(25, mMainToolbar.getContentInsetRight());
assertEquals(20, mMainToolbar.getContentInsetEnd());
- mMainToolbar.setContentInsetsRelative(40, 20);
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(40, 20));
assertEquals(20, mMainToolbar.getContentInsetLeft());
assertEquals(40, mMainToolbar.getContentInsetStart());
assertEquals(40, mMainToolbar.getContentInsetRight());
assertEquals(20, mMainToolbar.getContentInsetEnd());
}
+ public void testCurrentContentInsetsLtr() {
+ mInstrumentation.runOnMainSync(
+ () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_LTR));
+
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(20, 25));
+ assertEquals(20, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetStartWithNavigation(50));
+ assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+ // Since we haven't configured the navigation icon itself, the current content insets
+ // should stay the same
+ assertEquals(20, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+ () -> mMainToolbar.setNavigationIcon(R.drawable.icon_green));
+ assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+ // Since we have configured the navigation icon, and the currently set start inset with
+ // navigation is bigger than currently set start content inset, we should be getting that
+ // bigger value now
+ assertEquals(50, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetEndWithActions(35));
+ assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+ // Since we haven't configured the menu content, the current content insets
+ // should stay the same
+ assertEquals(50, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+ () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+ assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+ // Since we have configured the menu content, and the currently set start inset with
+ // navigation is bigger than currently set end content inset, we should be getting that
+ // bigger value now
+ assertEquals(50, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(35, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(35, mMainToolbar.getCurrentContentInsetEnd());
+ }
+
+ public void testCurrentContentInsetsRtl() {
+ mInstrumentation.runOnMainSync(
+ () -> mMainToolbar.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
+
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetsRelative(20, 25));
+ assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(20, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetStartWithNavigation(50));
+ assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+ // Since we haven't configured the navigation icon itself, the current content insets
+ // should stay the same
+ assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(20, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(20, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+ () -> mMainToolbar.setNavigationIcon(R.drawable.icon_green));
+ assertEquals(50, mMainToolbar.getContentInsetStartWithNavigation());
+ // Since we have configured the navigation icon, and the currently set start inset with
+ // navigation is bigger than currently set start content inset, we should be getting that
+ // bigger value now
+ assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.setContentInsetEndWithActions(35));
+ assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+ // Since we haven't configured the menu content, the current content insets
+ // should stay the same
+ assertEquals(25, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(25, mMainToolbar.getCurrentContentInsetEnd());
+
+ ViewTestUtils.runOnMainAndDrawSync(mInstrumentation, mMainToolbar,
+ () -> mMainToolbar.inflateMenu(R.menu.toolbar_menu));
+ assertEquals(35, mMainToolbar.getContentInsetEndWithActions());
+ // Since we have configured the menu content, and the currently set start inset with
+ // navigation is bigger than currently set end content inset, we should be getting that
+ // bigger value now
+ assertEquals(35, mMainToolbar.getCurrentContentInsetLeft());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetStart());
+ assertEquals(50, mMainToolbar.getCurrentContentInsetRight());
+ assertEquals(35, mMainToolbar.getCurrentContentInsetEnd());
+ }
+
@UiThreadTest
public void testPopupTheme() {
mMainToolbar.setPopupTheme(R.style.ToolbarPopupTheme_Test);
@@ -377,7 +461,7 @@
verify(mockListener, never()).onClick(any(View.class));
- getInstrumentation().runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
+ mInstrumentation.runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
verify(mockListener, times(1)).onClick(any(View.class));
verifyNoMoreInteractions(mockListener);
diff --git a/tests/tests/widget/src/android/widget/cts/util/TestUtils.java b/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
index 8d8f573..97d8df1 100644
--- a/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/TestUtils.java
@@ -16,20 +16,25 @@
package android.widget.cts.util;
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
import android.util.Pair;
import android.view.View;
import android.view.ViewParent;
import junit.framework.Assert;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Matchers.argThat;
+
public class TestUtils {
/**
* This method takes a view and returns a single bitmap that is the layered combination
@@ -100,7 +105,8 @@
}
/**
- * Checks whether all the pixels in the specified View are of the same specified color.
+ * Checks whether all the pixels in the specified of the {@link View} are
+ * filled with the specific color.
*
* In case there is a color mismatch, the behavior of this method depends on the
* <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
@@ -109,7 +115,26 @@
*/
public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull View view,
@ColorInt int color, int allowedComponentVariance, boolean throwExceptionIfFails) {
+ assertRegionPixelsOfColor(failMessagePrefix, view,
+ new Rect(0, 0, view.getWidth(), view.getHeight()),
+ color, allowedComponentVariance, throwExceptionIfFails);
+ }
+
+ /**
+ * Checks whether all the pixels in the specific rectangular region of the {@link View} are
+ * filled with the specific color.
+ *
+ * In case there is a color mismatch, the behavior of this method depends on the
+ * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+ * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+ * <code>Assert.fail</code> with detailed description of the mismatch.
+ */
+ public static void assertRegionPixelsOfColor(String failMessagePrefix, @NonNull View view,
+ @NonNull Rect region, @ColorInt int color, int allowedComponentVariance,
+ boolean throwExceptionIfFails) {
// Create a bitmap
+ final int viewWidth = view.getWidth();
+ final int viewHeight = view.getHeight();
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
Bitmap.Config.ARGB_8888);
// Create a canvas that wraps the bitmap
@@ -118,7 +143,7 @@
view.draw(canvas);
try {
- assertAllPixelsOfColor(failMessagePrefix, bitmap, view.getWidth(), view.getHeight(),
+ assertAllPixelsOfColor(failMessagePrefix, bitmap, region,
color, allowedComponentVariance, throwExceptionIfFails);
} finally {
bitmap.recycle();
@@ -126,7 +151,8 @@
}
/**
- * Checks whether all the pixels in the specified drawable are of the same specified color.
+ * Checks whether all the pixels in the specified {@link Drawable} are filled with the specific
+ * color.
*
* In case there is a color mismatch, the behavior of this method depends on the
* <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
@@ -136,20 +162,25 @@
public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
int allowedComponentVariance, boolean throwExceptionIfFails) {
- // Create a bitmap
- Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight,
- Bitmap.Config.ARGB_8888);
- // Create a canvas that wraps the bitmap
- Canvas canvas = new Canvas(bitmap);
- if (callSetBounds) {
- // Configure the drawable to have bounds that match the passed size
- drawable.setBounds(0, 0, drawableWidth, drawableHeight);
- }
- // And ask the drawable to draw itself to the canvas / bitmap
- drawable.draw(canvas);
+ // Create a bitmap
+ Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight,
+ Bitmap.Config.ARGB_8888);
+ // Create a canvas that wraps the bitmap
+ Canvas canvas = new Canvas(bitmap);
+ if (callSetBounds) {
+ // Configure the drawable to have bounds that match the passed size
+ drawable.setBounds(0, 0, drawableWidth, drawableHeight);
+ } else {
+ // Query the current bounds of the drawable for translation
+ Rect drawableBounds = drawable.getBounds();
+ canvas.translate(-drawableBounds.left, -drawableBounds.top);
+ }
+ // And ask the drawable to draw itself to the canvas / bitmap
+ drawable.draw(canvas);
try {
- assertAllPixelsOfColor(failMessagePrefix, bitmap, drawableWidth, drawableHeight, color,
+ assertAllPixelsOfColor(failMessagePrefix, bitmap,
+ new Rect(0, 0, drawableWidth, drawableHeight), color,
allowedComponentVariance, throwExceptionIfFails);
} finally {
bitmap.recycle();
@@ -157,49 +188,39 @@
}
/**
- * Checks whether all the pixels in the specified bitmap are of the same specified color.
+ * Checks whether all the pixels in the specific rectangular region of the bitmap are filled
+ * with the specific color.
*
* In case there is a color mismatch, the behavior of this method depends on the
* <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
* throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
* <code>Assert.fail</code> with detailed description of the mismatch.
*/
- public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
- int bitmapWidth, int bitmapHeight, @ColorInt int color,
- int allowedComponentVariance, boolean throwExceptionIfFails) {
- int[] rowPixels = new int[bitmapWidth];
- for (int row = 0; row < bitmapHeight; row++) {
+ private static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
+ @NonNull Rect region, @ColorInt int color, int allowedComponentVariance,
+ boolean throwExceptionIfFails) {
+ final int bitmapWidth = bitmap.getWidth();
+ final int bitmapHeight = bitmap.getHeight();
+ final int[] rowPixels = new int[bitmapWidth];
+
+ final int startRow = region.top;
+ final int endRow = region.bottom;
+ final int startColumn = region.left;
+ final int endColumn = region.right;
+
+ for (int row = startRow; row < endRow; row++) {
bitmap.getPixels(rowPixels, 0, bitmapWidth, 0, row, bitmapWidth, 1);
- for (int column = 0; column < bitmapWidth; column++) {
- int sourceAlpha = Color.alpha(rowPixels[column]);
- int sourceRed = Color.red(rowPixels[column]);
- int sourceGreen = Color.green(rowPixels[column]);
- int sourceBlue = Color.blue(rowPixels[column]);
-
- int expectedAlpha = Color.alpha(color);
- int expectedRed = Color.red(color);
- int expectedGreen = Color.green(color);
- int expectedBlue = Color.blue(color);
-
- int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
- int varianceRed = Math.abs(sourceRed - expectedRed);
- int varianceGreen = Math.abs(sourceGreen - expectedGreen);
- int varianceBlue = Math.abs(sourceBlue - expectedBlue);
-
- boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
- && (varianceRed <= allowedComponentVariance)
- && (varianceGreen <= allowedComponentVariance)
- && (varianceBlue <= allowedComponentVariance);
-
- if (!isColorMatch) {
+ for (int column = startColumn; column < endColumn; column++) {
+ @ColorInt int colorAtCurrPixel = rowPixels[column];
+ if (!areColorsTheSameWithTolerance(color, colorAtCurrPixel,
+ allowedComponentVariance)) {
String mismatchDescription = failMessagePrefix
- + ": expected all drawable colors to be ["
- + expectedAlpha + "," + expectedRed + ","
- + expectedGreen + "," + expectedBlue
- + "] but at position (" + row + "," + column + ") out of ("
- + bitmapWidth + "," + bitmapHeight + ") found ["
- + sourceAlpha + "," + sourceRed + ","
- + sourceGreen + "," + sourceBlue + "]";
+ + ": expected all bitmap colors in rectangle [l="
+ + startColumn + ", t=" + startRow + ", r=" + endColumn
+ + ", b=" + endRow + "] to be " + formatColorToHex(color)
+ + " but at position (" + row + "," + column + ") out of ("
+ + bitmapWidth + "," + bitmapHeight + ") found "
+ + formatColorToHex(colorAtCurrPixel);
if (throwExceptionIfFails) {
throw new RuntimeException(mismatchDescription);
} else {
@@ -209,4 +230,115 @@
}
}
}
+
+ /**
+ * Checks whether the center pixel in the specified bitmap is of the same specified color.
+ *
+ * In case there is a color mismatch, the behavior of this method depends on the
+ * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+ * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+ * <code>Assert.fail</code> with detailed description of the mismatch.
+ */
+ public static void assertCenterPixelOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
+ @ColorInt int color,
+ int allowedComponentVariance, boolean throwExceptionIfFails) {
+ final int centerX = bitmap.getWidth() / 2;
+ final int centerY = bitmap.getHeight() / 2;
+ final @ColorInt int colorAtCenterPixel = bitmap.getPixel(centerX, centerY);
+ if (!areColorsTheSameWithTolerance(color, colorAtCenterPixel,
+ allowedComponentVariance)) {
+ String mismatchDescription = failMessagePrefix
+ + ": expected all drawable colors to be "
+ + formatColorToHex(color)
+ + " but at position (" + centerX + "," + centerY + ") out of ("
+ + bitmap.getWidth() + "," + bitmap.getHeight() + ") found"
+ + formatColorToHex(colorAtCenterPixel);
+ if (throwExceptionIfFails) {
+ throw new RuntimeException(mismatchDescription);
+ } else {
+ Assert.fail(mismatchDescription);
+ }
+ }
+ }
+
+ /**
+ * Formats the passed integer-packed color into the #AARRGGBB format.
+ */
+ public static String formatColorToHex(@ColorInt int color) {
+ return String.format("#%08X", (0xFFFFFFFF & color));
+ }
+
+ /**
+ * Compares two integer-packed colors to be equal, each component within the specified
+ * allowed variance. Returns <code>true</code> if the two colors are sufficiently equal
+ * and <code>false</code> otherwise.
+ */
+ private static boolean areColorsTheSameWithTolerance(@ColorInt int expectedColor,
+ @ColorInt int actualColor, int allowedComponentVariance) {
+ int sourceAlpha = Color.alpha(actualColor);
+ int sourceRed = Color.red(actualColor);
+ int sourceGreen = Color.green(actualColor);
+ int sourceBlue = Color.blue(actualColor);
+
+ int expectedAlpha = Color.alpha(expectedColor);
+ int expectedRed = Color.red(expectedColor);
+ int expectedGreen = Color.green(expectedColor);
+ int expectedBlue = Color.blue(expectedColor);
+
+ int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
+ int varianceRed = Math.abs(sourceRed - expectedRed);
+ int varianceGreen = Math.abs(sourceGreen - expectedGreen);
+ int varianceBlue = Math.abs(sourceBlue - expectedBlue);
+
+ boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
+ && (varianceRed <= allowedComponentVariance)
+ && (varianceGreen <= allowedComponentVariance)
+ && (varianceBlue <= allowedComponentVariance);
+
+ return isColorMatch;
+ }
+
+ /**
+ * Composite two potentially translucent colors over each other and returns the result.
+ */
+ public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
+ int bgAlpha = Color.alpha(background);
+ int fgAlpha = Color.alpha(foreground);
+ int a = compositeAlpha(fgAlpha, bgAlpha);
+
+ int r = compositeComponent(Color.red(foreground), fgAlpha,
+ Color.red(background), bgAlpha, a);
+ int g = compositeComponent(Color.green(foreground), fgAlpha,
+ Color.green(background), bgAlpha, a);
+ int b = compositeComponent(Color.blue(foreground), fgAlpha,
+ Color.blue(background), bgAlpha, a);
+
+ return Color.argb(a, r, g, b);
+ }
+
+ private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
+ return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
+ }
+
+ private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
+ if (a == 0) return 0;
+ return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
+ }
+
+ public static CharSequence sameCharSequence(final CharSequence expected) {
+ return argThat(new BaseMatcher<CharSequence>() {
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof CharSequence) {
+ return expected.toString().compareTo(o.toString()) == 0;
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("doesn't match " + expected);
+ }
+ });
+ }
}
\ No newline at end of file
diff --git a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
index e9ef867..94389f0 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ViewTestUtils.java
@@ -16,14 +16,15 @@
package android.widget.cts.util;
-import junit.framework.Assert;
-
import android.app.Instrumentation;
+import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnDrawListener;
+import junit.framework.Assert;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -34,8 +35,8 @@
public class ViewTestUtils {
/**
- * Runs the specified Runnable on the main thread and ensures that the
- * specified View's tree is drawn before returning.
+ * Runs the specified Runnable on the main thread and ensures that the specified View's tree is
+ * drawn before returning.
*
* @param instrumentation the instrumentation used to run the test
* @param view the view whose tree should be drawn before returning
@@ -72,4 +73,94 @@
throw new RuntimeException(e);
}
}
-}
+
+ /**
+ * Emulates a tap in the center of the passed {@link View}.
+ *
+ * @param instrumentation the instrumentation used to run the test
+ * @param view the view to "tap"
+ */
+ public static void emulateTapOnViewCenter(Instrumentation instrumentation, View view) {
+ emulateTapOnScreen(instrumentation, view, view.getWidth() / 2, view.getHeight() / 2);
+ }
+
+ /**
+ * Emulates a tap on a point relative to the top-left corner of the passed {@link View}. Offset
+ * parameters are used to compute the final screen coordinates of the tap point.
+ *
+ * @param instrumentation the instrumentation used to run the test
+ * @param anchorView the anchor view to determine the tap location on the screen
+ * @param offsetX extra X offset for the tap
+ * @param offsetY extra Y offset for the tap
+ */
+ public static void emulateTapOnScreen(Instrumentation instrumentation, View anchorView,
+ int offsetX, int offsetY) {
+ // Use instrumentation to emulate a tap on the spinner to bring down its popup
+ final int[] viewOnScreenXY = new int[2];
+ anchorView.getLocationOnScreen(viewOnScreenXY);
+ int emulatedTapX = viewOnScreenXY[0] + offsetX;
+ int emulatedTapY = viewOnScreenXY[1] + offsetY;
+
+ // Inject DOWN event
+ long downTime = SystemClock.uptimeMillis();
+ MotionEvent eventDown = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
+ instrumentation.sendPointerSync(eventDown);
+
+ // Inject MOVE event
+ long moveTime = SystemClock.uptimeMillis();
+ MotionEvent eventMove = MotionEvent.obtain(
+ moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
+ instrumentation.sendPointerSync(eventMove);
+
+ // Inject UP event
+ long upTime = SystemClock.uptimeMillis();
+ MotionEvent eventUp = MotionEvent.obtain(
+ upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
+ instrumentation.sendPointerSync(eventUp);
+
+ // Wait for the system to process all events in the queue
+ instrumentation.waitForIdleSync();
+ }
+
+ /**
+ * Emulates a drag gesture across the screen.
+ *
+ * @param instrumentation the instrumentation used to run the test
+ * @param dragStartX Start X of the emulated drag gesture
+ * @param dragStartY Start Y of the emulated drag gesture
+ * @param dragAmountX X amount of the emulated drag gesture
+ * @param dragAmountY Y amount of the emulated drag gesture
+ */
+ public static void emulateDragGesture(Instrumentation instrumentation,
+ int dragStartX, int dragStartY, int dragAmountX, int dragAmountY) {
+ // Inject DOWN event
+ long downTime = SystemClock.uptimeMillis();
+ MotionEvent eventDown = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_DOWN, dragStartX, dragStartY, 1);
+ instrumentation.sendPointerSync(eventDown);
+
+ // Inject a sequence of MOVE events that emulate a "swipe down" gesture
+ final int moveEventCount = 20;
+ for (int i = 0; i < moveEventCount; i++) {
+ long moveTime = SystemClock.uptimeMillis();
+ final int moveX = dragStartX + dragAmountX * i / moveEventCount;
+ final int moveY = dragStartY + dragAmountY * i / moveEventCount;
+ MotionEvent eventMove = MotionEvent.obtain(
+ moveTime, moveTime, MotionEvent.ACTION_MOVE, moveX, moveY, 1);
+ instrumentation.sendPointerSync(eventMove);
+ // sleep for a bit to emulate a 2-second swipe
+ SystemClock.sleep(2000 / moveEventCount);
+ }
+
+ // Inject UP event
+ long upTime = SystemClock.uptimeMillis();
+ MotionEvent eventUp = MotionEvent.obtain(
+ upTime, upTime, MotionEvent.ACTION_UP, dragStartX + dragAmountX,
+ dragStartY + dragAmountY, 1);
+ instrumentation.sendPointerSync(eventUp);
+
+ // Wait for the system to process all events in the queue
+ instrumentation.waitForIdleSync();
+ }
+}
\ No newline at end of file