Merge "Add baseline and line height attributes" into pi-preview1-androidx-dev am: 374f3212da
am: 4175d378ab
Change-Id: If53c2c653219e363a6464cecbcdb668436feebd4
diff --git a/app-toolkit/common/src/main/java/androidx/arch/core/internal/SafeIterableMap.java b/app-toolkit/common/src/main/java/androidx/arch/core/internal/SafeIterableMap.java
index ef09098..f57efb0 100644
--- a/app-toolkit/common/src/main/java/androidx/arch/core/internal/SafeIterableMap.java
+++ b/app-toolkit/common/src/main/java/androidx/arch/core/internal/SafeIterableMap.java
@@ -230,6 +230,7 @@
return mNext != null;
}
+ @SuppressWarnings("ReferenceEquality")
@Override
public void supportRemove(@NonNull Entry<K, V> entry) {
if (mExpectedEnd == entry && entry == mNext) {
@@ -246,6 +247,7 @@
}
}
+ @SuppressWarnings("ReferenceEquality")
private Entry<K, V> nextNode() {
if (mNext == mExpectedEnd || mExpectedEnd == null) {
return null;
@@ -302,6 +304,7 @@
private Entry<K, V> mCurrent;
private boolean mBeforeStart = true;
+ @SuppressWarnings("ReferenceEquality")
@Override
public void supportRemove(@NonNull Entry<K, V> entry) {
if (entry == mCurrent) {
@@ -369,6 +372,7 @@
return mKey + "=" + mValue;
}
+ @SuppressWarnings("ReferenceEquality")
@Override
public boolean equals(Object obj) {
if (obj == this) {
diff --git a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
index 9ee229a..861dc72 100644
--- a/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
@@ -44,6 +44,8 @@
"-Xep:JavaLangClash:ERROR",
"-Xep:PrivateConstructorForUtilityClass:ERROR",
"-Xep:TypeParameterUnusedInFormals:ERROR",
+ "-Xep:StringSplitter:ERROR",
+ "-Xep:ReferenceEquality:ERROR",
// Nullaway
"-XepIgnoreUnknownCheckNames", // https://github.com/uber/NullAway/issues/25
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 9466f0c..9ba3c38 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -47,7 +47,6 @@
const val LOCALBROADCASTMANAGER = "androidx.localbroadcastmanager"
const val MEDIA = "androidx.media"
const val MEDIAROUTER = "androidx.mediarouter"
- const val MEDIAWIDGET = "androidx.mediawidget"
const val PALETTE = "androidx.palette"
const val PERCENTLAYOUT = "androidx.percentlayout"
const val PREFERENCE = "androidx.preference"
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
index a278051..6f0b3e0 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
@@ -65,6 +65,20 @@
VersionFileWriterTask.setUpAndroidLibrary(project, library)
DiffAndDocs.registerAndroidProject(project, library, supportLibraryExtension)
+
+ library.libraryVariants.all { libraryVariant ->
+ if (libraryVariant.getBuildType().getName().equals("debug")) {
+ @Suppress("DEPRECATION")
+ val javaCompile = libraryVariant.javaCompile
+ if (supportLibraryExtension.failOnUncheckedWarnings) {
+ javaCompile.options.compilerArgs.add("-Xlint:unchecked")
+ }
+ if (supportLibraryExtension.failOnDeprecationWarnings) {
+ javaCompile.options.compilerArgs.add("-Xlint:deprecation")
+ }
+ javaCompile.options.compilerArgs.add("-Werror")
+ }
+ }
}
project.apply(mapOf("plugin" to "com.android.library"))
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
index e8bd816..cee2955 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
@@ -23,6 +23,7 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
+import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile
/**
@@ -47,6 +48,11 @@
convention.targetCompatibility = JavaVersion.VERSION_1_7
}
DiffAndDocs.registerJavaProject(project, supportLibraryExtension)
+
+ project.tasks.withType(Jar::class.java) { jarTask ->
+ jarTask.setReproducibleFileOrder(true)
+ jarTask.setPreserveFileTimestamps(false)
+ }
}
project.apply(mapOf("plugin" to ErrorProneBasePlugin::class.java))
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
index d2a6ddb..9558f76 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
@@ -20,6 +20,7 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
+import org.gradle.api.tasks.bundling.Jar
class SupportKotlinLibraryPlugin : Plugin<Project> {
override fun apply(project: Project) {
@@ -38,6 +39,12 @@
convention.sourceCompatibility = JavaVersion.VERSION_1_7
convention.targetCompatibility = JavaVersion.VERSION_1_7
}
+
+ project.tasks.withType(Jar::class.java) { jarTask ->
+ jarTask.setReproducibleFileOrder(true)
+ jarTask.setPreserveFileTimestamps(false)
+ }
+
}
CheckExternalDependencyLicensesTask.configure(project)
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt b/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
index 4f69460..98528bb 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
@@ -34,6 +34,9 @@
private var licenses: MutableCollection<License> = ArrayList()
var java8Library = false
var publish = false
+ var failOnUncheckedWarnings = true
+ var failOnDeprecationWarnings = true
+
/**
* This flag works only if publish flag is "true".
* It is useful for modules that are used for tooling. For example room annotation
diff --git a/car/build.gradle b/car/build.gradle
index 52d2a40..d2e9be6 100644
--- a/car/build.gradle
+++ b/car/build.gradle
@@ -9,7 +9,8 @@
dependencies {
api project(':appcompat')
api project(':cardview')
- api "com.android.temp.support:design-widget:28.0.0-alpha1", {
+ api "com.android.temp.support:design-widget:28.0.0-alpha1@aar", {
+ transitive = true
exclude group: 'androidx.annotation'
exclude group: 'androidx.core'
exclude group: 'androidx.legacy'
@@ -54,4 +55,5 @@
description = "Android Car Support UI"
java8Library = true
minSdkVersion = 24
+ failOnUncheckedWarnings = false
}
diff --git a/cardview/build.gradle b/cardview/build.gradle
index d583284..c950dac 100644
--- a/cardview/build.gradle
+++ b/cardview/build.gradle
@@ -22,4 +22,5 @@
mavenGroup = LibraryGroups.CARDVIEW
inceptionYear = "2011"
description = "Android Support CardView v7"
+ failOnDeprecationWarnings = false
}
diff --git a/compat/api/current.txt b/compat/api/current.txt
index 0a19457..88eac66 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -809,6 +809,11 @@
method public static long getLongVersionCode(android.content.pm.PackageInfo);
}
+ public final class PermissionInfoCompat {
+ method public static int getProtection(android.content.pm.PermissionInfo);
+ method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+ }
+
public class ShortcutInfoCompat {
method public android.content.ComponentName getActivity();
method public java.lang.CharSequence getDisabledMessage();
diff --git a/compat/build.gradle b/compat/build.gradle
index 940819b..e4a719a 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -37,4 +37,6 @@
mavenGroup = LibraryGroups.CORE
inceptionYear = "2015"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/compat/src/androidTest/java/androidx/core/content/pm/PermissionInfoCompatTest.java b/compat/src/androidTest/java/androidx/core/content/pm/PermissionInfoCompatTest.java
new file mode 100644
index 0000000..79613be
--- /dev/null
+++ b/compat/src/androidTest/java/androidx/core/content/pm/PermissionInfoCompatTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.content.pm;
+
+import android.content.pm.PermissionInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PermissionInfoCompatTest {
+ @Test
+ public void testGetProtectionAndFlags() {
+ PermissionInfo pi = new PermissionInfo();
+
+ pi.protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
+ | PermissionInfo.PROTECTION_FLAG_PRIVILEGED;
+
+ Assert.assertEquals(PermissionInfo.PROTECTION_DANGEROUS,
+ PermissionInfoCompat.getProtection(pi));
+
+ Assert.assertEquals(PermissionInfo.PROTECTION_FLAG_PRIVILEGED,
+ PermissionInfoCompat.getProtectionFlags(pi));
+
+ pi.protectionLevel = 0xf | 0xfff0;
+ Assert.assertEquals(0xf, PermissionInfoCompat.getProtection(pi));
+ Assert.assertEquals(0xfff0, PermissionInfoCompat.getProtectionFlags(pi));
+ }
+}
diff --git a/compat/src/main/java/androidx/core/app/NotificationManagerCompat.java b/compat/src/main/java/androidx/core/app/NotificationManagerCompat.java
index 3660de3..e8b6188 100644
--- a/compat/src/main/java/androidx/core/app/NotificationManagerCompat.java
+++ b/compat/src/main/java/androidx/core/app/NotificationManagerCompat.java
@@ -267,7 +267,7 @@
// Parse the string again if it is different from the last time this method was called.
if (enabledNotificationListeners != null
&& !enabledNotificationListeners.equals(sEnabledNotificationListeners)) {
- final String[] components = enabledNotificationListeners.split(":");
+ final String[] components = enabledNotificationListeners.split(":", -1);
Set<String> packageNames = new HashSet<String>(components.length);
for (String component : components) {
ComponentName componentName = ComponentName.unflattenFromString(component);
diff --git a/compat/src/main/java/androidx/core/content/pm/PermissionInfoCompat.java b/compat/src/main/java/androidx/core/content/pm/PermissionInfoCompat.java
new file mode 100644
index 0000000..df095a6
--- /dev/null
+++ b/compat/src/main/java/androidx/core/content/pm/PermissionInfoCompat.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.content.pm;
+
+import android.annotation.SuppressLint;
+import android.content.pm.PermissionInfo;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.os.BuildCompat;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Helper for accessing features in {@link PermissionInfo}.
+ */
+public final class PermissionInfoCompat {
+ private PermissionInfoCompat() {
+ }
+
+ /** @hide */
+ @IntDef(flag = false, value = {
+ PermissionInfo.PROTECTION_NORMAL,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ PermissionInfo.PROTECTION_SIGNATURE,
+ PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM,
+ })
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Protection {}
+
+ /** @hide */
+ @SuppressLint("UniqueConstants") // because _SYSTEM and _PRIVILEGED are aliases.
+ @IntDef(flag = true, value = {
+ PermissionInfo.PROTECTION_FLAG_PRIVILEGED,
+ PermissionInfo.PROTECTION_FLAG_SYSTEM,
+ PermissionInfo.PROTECTION_FLAG_DEVELOPMENT,
+ PermissionInfo.PROTECTION_FLAG_APPOP,
+ PermissionInfo.PROTECTION_FLAG_PRE23,
+ PermissionInfo.PROTECTION_FLAG_INSTALLER,
+ PermissionInfo.PROTECTION_FLAG_VERIFIER,
+ PermissionInfo.PROTECTION_FLAG_PREINSTALLED,
+ PermissionInfo.PROTECTION_FLAG_SETUP,
+ PermissionInfo.PROTECTION_FLAG_INSTANT,
+ PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY,
+ })
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProtectionFlags {}
+
+ /**
+ * Return the base permission type of a {@link PermissionInfo}.
+ */
+ @SuppressLint("WrongConstant") // for "PermissionInfo.PROTECTION_MASK_BASE"
+ @Protection
+ public static int getProtection(@NonNull PermissionInfo permissionInfo) {
+ if (BuildCompat.isAtLeastP()) {
+ return permissionInfo.getProtection();
+ } else {
+ return permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+ }
+ }
+
+ /**
+ * Return the additional protection flags of a {@link PermissionInfo}.
+ */
+ @SuppressLint("WrongConstant") // for "~PermissionInfo.PROTECTION_MASK_BASE"
+ @ProtectionFlags
+ public static int getProtectionFlags(@NonNull PermissionInfo permissionInfo) {
+ if (BuildCompat.isAtLeastP()) {
+ return permissionInfo.getProtectionFlags();
+ } else {
+ return permissionInfo.protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
+ }
+ }
+}
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java b/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
index 366ddf3..4c296ea 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
@@ -569,6 +569,58 @@
return bundle;
}
+ @Override
+ public String toString() {
+ if (mType == TYPE_UNKOWN) {
+ return String.valueOf(mObj1);
+ }
+ final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
+ switch (mType) {
+ case TYPE_BITMAP:
+ case TYPE_ADAPTIVE_BITMAP:
+ sb.append(" size=")
+ .append(((Bitmap) mObj1).getWidth())
+ .append("x")
+ .append(((Bitmap) mObj1).getHeight());
+ break;
+ case TYPE_RESOURCE:
+ sb.append(" pkg=")
+ .append(getResPackage())
+ .append(" id=")
+ .append(String.format("0x%08x", getResId()));
+ break;
+ case TYPE_DATA:
+ sb.append(" len=").append(mInt1);
+ if (mInt2 != 0) {
+ sb.append(" off=").append(mInt2);
+ }
+ break;
+ case TYPE_URI:
+ sb.append(" uri=").append(mObj1);
+ break;
+ }
+ if (mTintList != null) {
+ sb.append(" tint=");
+ sb.append(mTintList);
+ }
+ if (mTintMode != DEFAULT_TINT_MODE) {
+ sb.append(" mode=").append(mTintMode);
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ private static String typeToString(int x) {
+ switch (x) {
+ case TYPE_BITMAP: return "BITMAP";
+ case TYPE_ADAPTIVE_BITMAP: return "BITMAP_MASKABLE";
+ case TYPE_DATA: return "DATA";
+ case TYPE_RESOURCE: return "RESOURCE";
+ case TYPE_URI: return "URI";
+ default: return "UNKNOWN";
+ }
+ }
+
/**
* Extracts an icon from a bundle that was added using {@link #toBundle()}.
*/
diff --git a/compat/src/main/java/androidx/core/os/LocaleHelper.java b/compat/src/main/java/androidx/core/os/LocaleHelper.java
index 001d657..5ce4c82 100644
--- a/compat/src/main/java/androidx/core/os/LocaleHelper.java
+++ b/compat/src/main/java/androidx/core/os/LocaleHelper.java
@@ -33,7 +33,7 @@
// Simpleton implementation for Locale.forLanguageTag(...)
static Locale forLanguageTag(String str) {
if (str.contains("-")) {
- String[] args = str.split("-");
+ String[] args = str.split("-", -1);
if (args.length > 2) {
return new Locale(args[0], args[1], args[2]);
} else if (args.length > 1) {
@@ -42,7 +42,7 @@
return new Locale(args[0]);
}
} else if (str.contains("_")) {
- String[] args = str.split("_");
+ String[] args = str.split("_", -1);
if (args.length > 2) {
return new Locale(args[0], args[1], args[2]);
} else if (args.length > 1) {
diff --git a/compat/src/main/java/androidx/core/os/LocaleListCompat.java b/compat/src/main/java/androidx/core/os/LocaleListCompat.java
index a933877..0be1ff3 100644
--- a/compat/src/main/java/androidx/core/os/LocaleListCompat.java
+++ b/compat/src/main/java/androidx/core/os/LocaleListCompat.java
@@ -289,7 +289,7 @@
if (list == null || list.isEmpty()) {
return getEmptyLocaleList();
} else {
- final String[] tags = list.split(",");
+ final String[] tags = list.split(",", -1);
final Locale[] localeArray = new Locale[tags.length];
for (int i = 0; i < localeArray.length; i++) {
localeArray[i] = Build.VERSION.SDK_INT >= 21
diff --git a/compat/src/main/java/androidx/core/os/LocaleListHelper.java b/compat/src/main/java/androidx/core/os/LocaleListHelper.java
index 0a656bc..137d9cd 100644
--- a/compat/src/main/java/androidx/core/os/LocaleListHelper.java
+++ b/compat/src/main/java/androidx/core/os/LocaleListHelper.java
@@ -273,7 +273,7 @@
if (list == null || list.isEmpty()) {
return getEmptyLocaleList();
} else {
- final String[] tags = list.split(",");
+ final String[] tags = list.split(",", -1);
final Locale[] localeArray = new Locale[tags.length];
for (int i = 0; i < localeArray.length; i++) {
localeArray[i] = LocaleHelper.forLanguageTag(tags[i]);
diff --git a/content/build.gradle b/content/build.gradle
index 25b01e5..d5f8b80 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -38,4 +38,5 @@
mavenGroup = LibraryGroups.CONTENTPAGING
inceptionYear = "2017"
description = "Library providing support for paging across content exposed via a ContentProvider. Use of this library allows a client to avoid expensive interprocess \"cursor window swaps\" on the UI thread."
+ failOnDeprecationWarnings = false
}
diff --git a/coordinatorlayout/build.gradle b/coordinatorlayout/build.gradle
index 8e72580..4775f67 100644
--- a/coordinatorlayout/build.gradle
+++ b/coordinatorlayout/build.gradle
@@ -39,4 +39,6 @@
mavenGroup = LibraryGroups.COORDINATORLAYOUT
inceptionYear = "2011"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/cursoradapter/build.gradle b/cursoradapter/build.gradle
index ce80655..2493a2b 100644
--- a/cursoradapter/build.gradle
+++ b/cursoradapter/build.gradle
@@ -16,4 +16,5 @@
mavenGroup = LibraryGroups.CURSORADAPTER
inceptionYear = "2018"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnDeprecationWarnings = false
}
diff --git a/customview/build.gradle b/customview/build.gradle
index 37cfc2f..f2ebd43 100644
--- a/customview/build.gradle
+++ b/customview/build.gradle
@@ -22,4 +22,5 @@
mavenGroup = LibraryGroups.CUSTOMVIEW
inceptionYear = "2018"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnDeprecationWarnings = false
}
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 637abb4..6da13e0 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -24,4 +24,5 @@
mavenGroup = LibraryGroups.DYNAMICANIMATION
inceptionYear = "2017"
description = "Physics-based animation in support library, where the animations are driven by physics force. You can use this Animation library to create smooth and realistic animations."
+ failOnUncheckedWarnings = false
}
\ No newline at end of file
diff --git a/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java b/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
index f697f24..d685bf1 100644
--- a/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
+++ b/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
@@ -3920,7 +3920,7 @@
break;
}
case IFD_FORMAT_USHORT: {
- final String[] values = value.split(",");
+ final String[] values = value.split(",", -1);
final int[] intArray = new int[values.length];
for (int j = 0; j < values.length; ++j) {
intArray[j] = Integer.parseInt(values[j]);
@@ -3930,7 +3930,7 @@
break;
}
case IFD_FORMAT_SLONG: {
- final String[] values = value.split(",");
+ final String[] values = value.split(",", -1);
final int[] intArray = new int[values.length];
for (int j = 0; j < values.length; ++j) {
intArray[j] = Integer.parseInt(values[j]);
@@ -3940,7 +3940,7 @@
break;
}
case IFD_FORMAT_ULONG: {
- final String[] values = value.split(",");
+ final String[] values = value.split(",", -1);
final long[] longArray = new long[values.length];
for (int j = 0; j < values.length; ++j) {
longArray[j] = Long.parseLong(values[j]);
@@ -3950,10 +3950,10 @@
break;
}
case IFD_FORMAT_URATIONAL: {
- final String[] values = value.split(",");
+ final String[] values = value.split(",", -1);
final Rational[] rationalArray = new Rational[values.length];
for (int j = 0; j < values.length; ++j) {
- final String[] numbers = values[j].split("/");
+ final String[] numbers = values[j].split("/", -1);
rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
(long) Double.parseDouble(numbers[1]));
}
@@ -3962,10 +3962,10 @@
break;
}
case IFD_FORMAT_SRATIONAL: {
- final String[] values = value.split(",");
+ final String[] values = value.split(",", -1);
final Rational[] rationalArray = new Rational[values.length];
for (int j = 0; j < values.length; ++j) {
- final String[] numbers = values[j].split("/");
+ final String[] numbers = values[j].split("/", -1);
rationalArray[j] = new Rational((long) Double.parseDouble(numbers[0]),
(long) Double.parseDouble(numbers[1]));
}
@@ -3974,7 +3974,7 @@
break;
}
case IFD_FORMAT_DOUBLE: {
- final String[] values = value.split(",");
+ final String[] values = value.split(",", -1);
final double[] doubleArray = new double[values.length];
for (int j = 0; j < values.length; ++j) {
doubleArray[j] = Double.parseDouble(values[j]);
@@ -4510,7 +4510,7 @@
setAttribute(TAG_GPS_SPEED_REF, "K");
setAttribute(TAG_GPS_SPEED, new Rational(location.getSpeed()
* TimeUnit.HOURS.toSeconds(1) / 1000).toString());
- String[] dateTime = sFormatter.format(new Date(location.getTime())).split("\\s+");
+ String[] dateTime = sFormatter.format(new Date(location.getTime())).split("\\s+", -1);
setAttribute(ExifInterface.TAG_GPS_DATESTAMP, dateTime[0]);
setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, dateTime[1]);
}
@@ -4643,18 +4643,18 @@
private static double convertRationalLatLonToDouble(String rationalString, String ref) {
try {
- String [] parts = rationalString.split(",");
+ String [] parts = rationalString.split(",", -1);
String [] pair;
- pair = parts[0].split("/");
+ pair = parts[0].split("/", -1);
double degrees = Double.parseDouble(pair[0].trim())
/ Double.parseDouble(pair[1].trim());
- pair = parts[1].split("/");
+ pair = parts[1].split("/", -1);
double minutes = Double.parseDouble(pair[0].trim())
/ Double.parseDouble(pair[1].trim());
- pair = parts[2].split("/");
+ pair = parts[2].split("/", -1);
double seconds = Double.parseDouble(pair[0].trim())
/ Double.parseDouble(pair[1].trim());
@@ -6017,7 +6017,7 @@
// See TIFF 6.0 Section 2, "Image File Directory".
// Take the first component if there are more than one component.
if (entryValue.contains(",")) {
- String[] entryValues = entryValue.split(",");
+ String[] entryValues = entryValue.split(",", -1);
Pair<Integer, Integer> dataFormat = guessDataFormat(entryValues[0]);
if (dataFormat.first == IFD_FORMAT_STRING) {
return dataFormat;
@@ -6049,7 +6049,7 @@
}
if (entryValue.contains("/")) {
- String[] rationalNumber = entryValue.split("/");
+ String[] rationalNumber = entryValue.split("/", -1);
if (rationalNumber.length == 2) {
try {
long numerator = (long) Double.parseDouble(rationalNumber[0]);
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 5f8954f..7faa903 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -30,4 +30,6 @@
mavenGroup = LibraryGroups.FRAGMENT
inceptionYear = "2011"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index 19a0366..423cb22 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -31,4 +31,5 @@
mavenGroup = LibraryGroups.VECTORDRAWABLE
inceptionYear = "2015"
description = "Android Support VectorDrawable"
+ failOnDeprecationWarnings = false
}
\ No newline at end of file
diff --git a/gridlayout/build.gradle b/gridlayout/build.gradle
index fb4dd10..930e191 100644
--- a/gridlayout/build.gradle
+++ b/gridlayout/build.gradle
@@ -21,4 +21,5 @@
mavenGroup = LibraryGroups.GRIDLAYOUT
inceptionYear = "2013"
description = "Android Support Grid Layout"
+ failOnDeprecationWarnings = false
}
diff --git a/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java b/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java
index 9b5df45..35d34d4 100644
--- a/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java
+++ b/heifwriter/src/main/java/androidx/heifwriter/EglWindowSurface.java
@@ -25,6 +25,8 @@
import android.util.Log;
import android.view.Surface;
+import java.util.Objects;
+
/**
* Holds state associated with a Surface used for MediaCodec encoder input.
* <p>
@@ -63,7 +65,7 @@
*/
private void eglSetup() {
mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
- if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
+ if (Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
throw new RuntimeException("unable to get EGL14 display");
}
int[] version = new int[2];
@@ -130,7 +132,7 @@
}
private void releaseEGLSurface() {
- if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+ if (!Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
mEGLSurface = EGL14.EGL_NO_SURFACE;
}
@@ -141,7 +143,7 @@
* Surface that was passed to our constructor.
*/
public void release() {
- if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+ if (!Objects.equals(mEGLDisplay, EGL14.EGL_NO_DISPLAY)) {
EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
EGL14.eglReleaseThread();
diff --git a/jetifier/jetifier/core/src/main/resources/default.config b/jetifier/jetifier/core/src/main/resources/default.config
index bec56c3..a4aeadf 100644
--- a/jetifier/jetifier/core/src/main/resources/default.config
+++ b/jetifier/jetifier/core/src/main/resources/default.config
@@ -1112,6 +1112,10 @@
"from": { "groupId": "com.android.support.test.uiautomator", "artifactId": "uiautomator-v18", "version": "28.0.0" },
"to": [{ "groupId": "androidx.test.uiautomator", "artifactId": "uiautomator", "version": "1.0.0" }]
},
+ {
+ "from": { "groupId": "com.android.support", "artifactId": "car", "version": "28.0.0" },
+ "to": [{ "groupId": "androidx.car", "artifactId": "car", "version": "1.0.0" }]
+ },
# Keep it same
{
"from": { "groupId": "com.android.support", "artifactId": "slices-core", "version": "28.0.0" },
diff --git a/jetifier/jetifier/core/src/main/resources/default.generated.config b/jetifier/jetifier/core/src/main/resources/default.generated.config
index 33ddfb7..3acc5fc 100644
--- a/jetifier/jetifier/core/src/main/resources/default.generated.config
+++ b/jetifier/jetifier/core/src/main/resources/default.generated.config
@@ -2104,6 +2104,20 @@
{
"from": {
"groupId": "com.android.support",
+ "artifactId": "car",
+ "version": "28.0.0"
+ },
+ "to": [
+ {
+ "groupId": "androidx.car",
+ "artifactId": "car",
+ "version": "1.0.0"
+ }
+ ]
+ },
+ {
+ "from": {
+ "groupId": "com.android.support",
"artifactId": "slices-core",
"version": "28.0.0"
},
@@ -2244,59 +2258,23 @@
],
"map": {
"types": {
+ "android/support/v4/widget/SlidingPaneLayout": "androidx/slidingpanelayout/widget/SlidingPaneLayout",
+ "android/support/v4/view/AccessibilityDelegateCompat": "androidx/core/view/AccessibilityDelegateCompat",
+ "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": "androidx/core/view/accessibility/AccessibilityNodeInfoCompat",
+ "android/support/v4/view/ViewCompat": "androidx/core/view/ViewCompat",
+ "android/support/v4/widget/ViewDragHelper": "androidx/customview/widget/ViewDragHelper",
"android/support/annotation/NonNull": "androidx/annotation/NonNull",
- "android/support/annotation/RestrictTo": "androidx/annotation/RestrictTo",
- "android/support/v4/os/BuildCompat": "androidx/core/os/BuildCompat",
"android/support/annotation/Nullable": "androidx/annotation/Nullable",
+ "android/support/v4/view/AbsSavedState": "androidx/customview/view/AbsSavedState",
"android/support/annotation/RequiresApi": "androidx/annotation/RequiresApi",
+ "android/support/annotation/Px": "androidx/annotation/Px",
"android/support/annotation/ColorInt": "androidx/annotation/ColorInt",
- "android/support/v7/widget/RecyclerView": "androidx/recyclerview/widget/RecyclerView",
- "android/support/v7/widget/LinearLayoutManager": "androidx/recyclerview/widget/LinearLayoutManager",
- "android/arch/lifecycle/LiveData": "androidx/lifecycle/LiveData",
- "android/arch/lifecycle/Observer": "androidx/lifecycle/Observer",
- "android/support/annotation/AttrRes": "androidx/annotation/AttrRes",
- "android/databinding/BindingAdapter": "androidx/databinding/BindingAdapter",
- "android/databinding/BindingMethod": "androidx/databinding/BindingMethod",
- "android/databinding/ObservableMap": "androidx/databinding/ObservableMap",
- "android/databinding/BindingBuildInfo": "androidx/databinding/BindingBuildInfo",
- "android/databinding/Observable": "androidx/databinding/Observable",
- "android/databinding/Untaggable": "androidx/databinding/Untaggable",
- "android/databinding/InverseBindingMethod": "androidx/databinding/InverseBindingMethod",
- "android/databinding/CallbackRegistry": "androidx/databinding/CallbackRegistry",
- "android/databinding/BindingMethods": "androidx/databinding/BindingMethods",
- "android/databinding/InverseBindingListener": "androidx/databinding/InverseBindingListener",
- "android/databinding/BindingConversion": "androidx/databinding/BindingConversion",
- "android/databinding/ObservableList": "androidx/databinding/ObservableList",
- "android/databinding/InverseBindingMethods": "androidx/databinding/InverseBindingMethods",
- "android/databinding/InverseMethod": "androidx/databinding/InverseMethod",
- "android/databinding/Bindable": "androidx/databinding/Bindable",
- "android/databinding/InverseBindingAdapter": "androidx/databinding/InverseBindingAdapter",
- "android/support/design/drawable/DrawableUtils": "android/support/design/drawable/DrawableUtils",
- "android/support/app/recommendation/ContentRecommendation": "androidx/recommendation/app/ContentRecommendation",
"android/support/annotation/DrawableRes": "androidx/annotation/DrawableRes",
- "android/support/app/recommendation/RecommendationExtender": "androidx/recommendation/app/RecommendationExtender",
- "android/arch/lifecycle/ErrorMessages": "androidx/lifecycle/ErrorMessages",
- "android/arch/lifecycle/model/EventMethod": "androidx/lifecycle/model/EventMethod",
- "android/arch/lifecycle/Elements_extKt": "androidx/lifecycle/Elements_extKt",
- "android/arch/lifecycle/WriterKt": "androidx/lifecycle/WriterKt",
- "android/arch/lifecycle/ObserversCollector": "androidx/lifecycle/ObserversCollector",
- "android/arch/lifecycle/Validator": "androidx/lifecycle/Validator",
- "android/arch/lifecycle/model/LifecycleObserverInfo": "androidx/lifecycle/model/LifecycleObserverInfo",
- "android/arch/lifecycle/model/AdapterClassKt": "androidx/lifecycle/model/AdapterClassKt",
- "android/arch/lifecycle/OnLifecycleEvent": "androidx/lifecycle/OnLifecycleEvent",
- "android/arch/lifecycle/Lifecycle": "androidx/lifecycle/Lifecycle",
- "android/arch/lifecycle/LifecycleObserver": "androidx/lifecycle/LifecycleObserver",
- "android/arch/lifecycle/model/EventMethodCall": "androidx/lifecycle/model/EventMethodCall",
- "android/arch/lifecycle/model/AdapterClass": "androidx/lifecycle/model/AdapterClass",
- "android/arch/lifecycle/model/InputModel": "androidx/lifecycle/model/InputModel",
- "android/arch/lifecycle/Lifecycling": "androidx/lifecycle/Lifecycling",
- "android/arch/lifecycle/LifecycleProcessor": "androidx/lifecycle/LifecycleProcessor",
- "android/arch/lifecycle/Input_collectorKt": "androidx/lifecycle/Input_collectorKt",
- "android/arch/lifecycle/TransformationKt": "androidx/lifecycle/TransformationKt",
- "android/arch/lifecycle/GeneratedAdapter": "androidx/lifecycle/GeneratedAdapter",
- "android/arch/lifecycle/LifecycleOwner": "androidx/lifecycle/LifecycleOwner",
- "android/arch/lifecycle/MethodCallsLogger": "androidx/lifecycle/MethodCallsLogger",
+ "android/support/v4/content/ContextCompat": "androidx/core/content/ContextCompat",
+ "android/support/v4/content/LocalBroadcastManager": "androidx/localbroadcastmanager/content/LocalBroadcastManager",
+ "android/support/v4/content/WakefulBroadcastReceiver": "androidx/legacy/content/WakefulBroadcastReceiver",
"android/support/v4/media/AudioAttributesCompat": "androidx/media/AudioAttributesCompat",
+ "android/support/annotation/RestrictTo": "androidx/annotation/RestrictTo",
"android/support/v4/media/AudioAttributesCompatApi21": "androidx/media/AudioAttributesCompatApi21",
"android/support/v4/media/MediaBrowserCompat": "android/support/v4/media/MediaBrowserCompat",
"android/support/v4/media/session/MediaSessionCompat": "android/support/v4/media/session/MediaSessionCompat",
@@ -2342,529 +2320,77 @@
"android/support/v4/media/session/MediaSessionCompatApi22": "android/support/v4/media/session/MediaSessionCompatApi22",
"android/support/v4/media/session/PlaybackStateCompatApi21": "android/support/v4/media/session/PlaybackStateCompatApi21",
"android/support/v4/media/session/PlaybackStateCompatApi22": "android/support/v4/media/session/PlaybackStateCompatApi22",
- "android/support/annotation/AnimRes": "androidx/annotation/AnimRes",
- "android/support/annotation/AnimatorRes": "androidx/annotation/AnimatorRes",
- "android/support/annotation/AnyRes": "androidx/annotation/AnyRes",
- "android/support/annotation/AnyThread": "androidx/annotation/AnyThread",
- "android/support/annotation/ArrayRes": "androidx/annotation/ArrayRes",
- "android/support/annotation/BinderThread": "androidx/annotation/BinderThread",
- "android/support/annotation/BoolRes": "androidx/annotation/BoolRes",
- "android/support/annotation/CallSuper": "androidx/annotation/CallSuper",
- "android/support/annotation/CheckResult": "androidx/annotation/CheckResult",
- "android/support/annotation/ColorLong": "androidx/annotation/ColorLong",
- "android/support/annotation/ColorRes": "androidx/annotation/ColorRes",
- "android/support/annotation/DimenRes": "androidx/annotation/DimenRes",
- "android/support/annotation/Dimension": "androidx/annotation/Dimension",
- "android/support/annotation/FloatRange": "androidx/annotation/FloatRange",
- "android/support/annotation/FontRes": "androidx/annotation/FontRes",
- "android/support/annotation/FractionRes": "androidx/annotation/FractionRes",
- "android/support/annotation/GuardedBy": "androidx/annotation/GuardedBy",
- "android/support/annotation/HalfFloat": "androidx/annotation/HalfFloat",
- "android/support/annotation/IdRes": "androidx/annotation/IdRes",
- "android/support/annotation/IntDef": "androidx/annotation/IntDef",
- "android/support/annotation/IntRange": "androidx/annotation/IntRange",
- "android/support/annotation/IntegerRes": "androidx/annotation/IntegerRes",
- "android/support/annotation/InterpolatorRes": "androidx/annotation/InterpolatorRes",
- "android/support/annotation/Keep": "androidx/annotation/Keep",
- "android/support/annotation/LayoutRes": "androidx/annotation/LayoutRes",
- "android/support/annotation/LongDef": "androidx/annotation/LongDef",
- "android/support/annotation/MainThread": "androidx/annotation/MainThread",
- "android/support/annotation/MenuRes": "androidx/annotation/MenuRes",
- "android/support/annotation/NavigationRes": "androidx/annotation/NavigationRes",
- "android/support/annotation/PluralsRes": "androidx/annotation/PluralsRes",
- "android/support/annotation/Px": "androidx/annotation/Px",
- "android/support/annotation/RawRes": "androidx/annotation/RawRes",
- "android/support/annotation/RequiresPermission": "androidx/annotation/RequiresPermission",
- "android/support/annotation/Size": "androidx/annotation/Size",
- "android/support/annotation/StringDef": "androidx/annotation/StringDef",
- "android/support/annotation/StringRes": "androidx/annotation/StringRes",
- "android/support/annotation/StyleRes": "androidx/annotation/StyleRes",
- "android/support/annotation/StyleableRes": "androidx/annotation/StyleableRes",
- "android/support/annotation/TransitionRes": "androidx/annotation/TransitionRes",
- "android/support/annotation/UiThread": "androidx/annotation/UiThread",
- "android/support/annotation/VisibleForTesting": "androidx/annotation/VisibleForTesting",
- "android/support/annotation/WorkerThread": "androidx/annotation/WorkerThread",
- "android/support/annotation/XmlRes": "androidx/annotation/XmlRes",
- "android/support/design/stateful/ExtendableSavedState": "android/support/design/stateful/ExtendableSavedState",
- "android/support/v4/view/AbsSavedState": "androidx/customview/view/AbsSavedState",
- "android/support/v4/util/SimpleArrayMap": "androidx/collection/SimpleArrayMap",
- "android/support/design/shape/CornerTreatment": "android/support/design/shape/CornerTreatment",
- "android/support/design/shape/ShapePath": "android/support/design/shape/ShapePath",
- "android/support/design/shape/CutCornerTreatment": "android/support/design/shape/CutCornerTreatment",
- "android/support/design/shape/EdgeTreatment": "android/support/design/shape/EdgeTreatment",
- "android/support/design/shape/InterpolateOnScrollPositionChangeHelper": "android/support/design/shape/InterpolateOnScrollPositionChangeHelper",
- "android/support/design/shape/MaterialShapeDrawable": "android/support/design/shape/MaterialShapeDrawable",
- "android/support/v4/graphics/drawable/TintAwareDrawable": "androidx/core/graphics/drawable/TintAwareDrawable",
- "android/support/design/shape/ShapePathModel": "android/support/design/shape/ShapePathModel",
- "android/support/design/shape/RoundedCornerTreatment": "android/support/design/shape/RoundedCornerTreatment",
- "android/support/design/shape/TriangleEdgeTreatment": "android/support/design/shape/TriangleEdgeTreatment",
- "android/support/v4/widget/DrawerLayout": "androidx/drawerlayout/widget/DrawerLayout",
- "android/support/v4/view/AccessibilityDelegateCompat": "androidx/core/view/AccessibilityDelegateCompat",
- "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": "androidx/core/view/accessibility/AccessibilityNodeInfoCompat",
- "android/support/v4/view/ViewCompat": "androidx/core/view/ViewCompat",
- "android/support/v4/widget/ViewDragHelper": "androidx/customview/widget/ViewDragHelper",
- "android/support/v4/content/ContextCompat": "androidx/core/content/ContextCompat",
- "android/support/v4/view/GravityCompat": "androidx/core/view/GravityCompat",
- "android/support/v4/graphics/drawable/DrawableCompat": "androidx/core/graphics/drawable/DrawableCompat",
- "android/support/design/ripple/RippleUtils": "android/support/design/ripple/RippleUtils",
- "android/support/v4/graphics/ColorUtils": "androidx/core/graphics/ColorUtils",
- "android/support/design/resources/MaterialResources": "android/support/design/resources/MaterialResources",
- "android/support/v7/content/res/AppCompatResources": "androidx/appcompat/content/res/AppCompatResources",
- "android/support/design/resources/TextAppearance": "android/support/design/resources/TextAppearance",
- "android/support/design/resources/R": "android/support/design/resources/R",
- "android/support/v4/content/res/ResourcesCompat": "androidx/core/content/res/ResourcesCompat",
- "android/arch/lifecycle/DefaultLifecycleObserver": "androidx/lifecycle/DefaultLifecycleObserver",
- "android/arch/lifecycle/FullLifecycleObserver": "androidx/lifecycle/FullLifecycleObserver",
- "android/support/multidex/ZipUtil": "androidx/multidex/ZipUtil",
- "android/support/multidex/MultiDexExtractor": "androidx/multidex/MultiDexExtractor",
- "android/support/multidex/MultiDex": "androidx/multidex/MultiDex",
- "android/support/multidex/MultiDexApplication": "androidx/multidex/MultiDexApplication",
- "android/support/v7/widget/CardView": "androidx/cardview/widget/CardView",
- "android/support/v7/widget/CardViewDelegate": "androidx/cardview/widget/CardViewDelegate",
- "android/support/v7/cardview/R": "androidx/cardview/R",
- "android/support/v7/widget/CardViewImpl": "androidx/cardview/widget/CardViewImpl",
- "android/support/v7/widget/CardViewApi21Impl": "androidx/cardview/widget/CardViewApi21Impl",
- "android/support/v7/widget/CardViewApi17Impl": "androidx/cardview/widget/CardViewApi17Impl",
- "android/support/v7/widget/CardViewBaseImpl": "androidx/cardview/widget/CardViewBaseImpl",
- "android/support/v7/widget/RoundRectDrawableWithShadow": "androidx/cardview/widget/RoundRectDrawableWithShadow",
- "android/support/v7/widget/RoundRectDrawable": "androidx/cardview/widget/RoundRectDrawable",
- "android/arch/persistence/room/DatabaseConfiguration": "androidx/room/DatabaseConfiguration",
- "android/arch/persistence/db/SupportSQLiteOpenHelper": "androidx/sqlite/db/SupportSQLiteOpenHelper",
- "android/arch/persistence/room/RoomDatabase": "androidx/room/RoomDatabase",
- "android/arch/persistence/room/EntityDeletionOrUpdateAdapter": "androidx/room/EntityDeletionOrUpdateAdapter",
- "android/arch/persistence/room/SharedSQLiteStatement": "androidx/room/SharedSQLiteStatement",
- "android/arch/persistence/db/SupportSQLiteStatement": "androidx/sqlite/db/SupportSQLiteStatement",
- "android/arch/persistence/room/EntityInsertionAdapter": "androidx/room/EntityInsertionAdapter",
- "android/arch/persistence/room/InvalidationTracker": "androidx/room/InvalidationTracker",
- "android/arch/persistence/db/SupportSQLiteDatabase": "androidx/sqlite/db/SupportSQLiteDatabase",
- "android/arch/core/internal/SafeIterableMap": "androidx/arch/core/internal/SafeIterableMap",
- "android/support/v4/util/ArraySet": "androidx/collection/ArraySet",
- "android/arch/core/executor/ArchTaskExecutor": "androidx/arch/core/executor/ArchTaskExecutor",
- "android/arch/persistence/room/Room": "androidx/room/Room",
- "android/arch/persistence/room/migration/Migration": "androidx/room/migration/Migration",
- "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory": "androidx/sqlite/db/framework/FrameworkSQLiteOpenHelperFactory",
- "android/support/v4/app/ActivityManagerCompat": "androidx/core/app/ActivityManagerCompat",
- "android/support/v4/util/SparseArrayCompat": "androidx/collection/SparseArrayCompat",
- "android/arch/persistence/db/SimpleSQLiteQuery": "androidx/sqlite/db/SimpleSQLiteQuery",
- "android/arch/persistence/db/SupportSQLiteQuery": "androidx/sqlite/db/SupportSQLiteQuery",
- "android/arch/persistence/room/RoomOpenHelper": "androidx/room/RoomOpenHelper",
- "android/arch/persistence/room/RoomMasterTable": "androidx/room/RoomMasterTable",
- "android/arch/persistence/room/RoomSQLiteQuery": "androidx/room/RoomSQLiteQuery",
- "android/arch/persistence/db/SupportSQLiteProgram": "androidx/sqlite/db/SupportSQLiteProgram",
- "android/arch/persistence/room/paging/LimitOffsetDataSource": "androidx/room/paging/LimitOffsetDataSource",
- "android/arch/paging/PositionalDataSource": "androidx/paging/PositionalDataSource",
- "android/arch/persistence/room/util/StringUtil": "androidx/room/util/StringUtil",
- "android/arch/persistence/room/util/TableInfo": "androidx/room/util/TableInfo",
- "android/arch/persistence/room/ColumnInfo": "androidx/room/ColumnInfo",
- "android/support/text/emoji/bundled/BundledEmojiCompatConfig": "androidx/emoji/bundled/BundledEmojiCompatConfig",
- "android/support/text/emoji/EmojiCompat": "androidx/emoji/text/EmojiCompat",
- "android/support/v4/util/Preconditions": "androidx/core/util/Preconditions",
- "android/support/text/emoji/MetadataRepo": "androidx/emoji/text/MetadataRepo",
- "android/support/v7/graphics/ColorCutQuantizer": "androidx/palette/graphics/ColorCutQuantizer",
- "android/support/v7/graphics/Palette": "androidx/palette/graphics/Palette",
- "android/support/v7/graphics/Target": "androidx/palette/graphics/Target",
- "android/arch/persistence/room/EmptyResultSetException": "androidx/room/EmptyResultSetException",
- "android/arch/persistence/room/RxRoom": "androidx/room/RxRoom",
- "android/support/v4/app/ActionBarDrawerToggle": "androidx/legacy/app/ActionBarDrawerToggle",
- "android/support/v4/widget/Space": "androidx/legacy/widget/Space",
- "android/support/animation/AnimationHandler": "androidx/dynamicanimation/animation/AnimationHandler",
- "android/support/animation/DynamicAnimation": "androidx/dynamicanimation/animation/DynamicAnimation",
- "android/support/animation/FloatPropertyCompat": "androidx/dynamicanimation/animation/FloatPropertyCompat",
- "android/support/animation/FloatValueHolder": "androidx/dynamicanimation/animation/FloatValueHolder",
- "android/support/animation/FlingAnimation": "androidx/dynamicanimation/animation/FlingAnimation",
- "android/support/animation/Force": "androidx/dynamicanimation/animation/Force",
- "android/support/animation/SpringAnimation": "androidx/dynamicanimation/animation/SpringAnimation",
- "android/support/animation/SpringForce": "androidx/dynamicanimation/animation/SpringForce",
- "android/arch/persistence/db/framework/FrameworkSQLiteDatabase": "androidx/sqlite/db/framework/FrameworkSQLiteDatabase",
- "android/arch/persistence/db/framework/FrameworkSQLiteProgram": "androidx/sqlite/db/framework/FrameworkSQLiteProgram",
- "android/arch/persistence/db/framework/FrameworkSQLiteStatement": "androidx/sqlite/db/framework/FrameworkSQLiteStatement",
- "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper": "androidx/sqlite/db/framework/FrameworkSQLiteOpenHelper",
- "android/arch/persistence/room/guava/GuavaRoom": "androidx/room/guava/GuavaRoom",
- "android/arch/lifecycle/LiveDataReactiveStreams": "androidx/lifecycle/LiveDataReactiveStreams",
- "android/support/v4/widget/CircleImageView": "androidx/swiperefreshlayout/widget/CircleImageView",
- "android/support/v4/widget/CircularProgressDrawable": "androidx/swiperefreshlayout/widget/CircularProgressDrawable",
- "android/support/v4/view/animation/FastOutSlowInInterpolator": "androidx/interpolator/view/animation/FastOutSlowInInterpolator",
- "android/support/v4/widget/SwipeRefreshLayout": "androidx/swiperefreshlayout/widget/SwipeRefreshLayout",
- "android/support/v4/view/NestedScrollingParent": "androidx/core/view/NestedScrollingParent",
- "android/support/v4/view/NestedScrollingChild": "androidx/core/view/NestedScrollingChild",
- "android/support/v4/view/NestedScrollingParentHelper": "androidx/core/view/NestedScrollingParentHelper",
- "android/support/v4/view/NestedScrollingChildHelper": "androidx/core/view/NestedScrollingChildHelper",
- "android/support/v4/widget/ListViewCompat": "androidx/core/widget/ListViewCompat",
- "android/support/design/bottomappbar/BottomAppBar": "android/support/design/bottomappbar/BottomAppBar",
- "android/support/design/bottomappbar/BottomAppBarTopEdgeTreatment": "android/support/design/bottomappbar/BottomAppBarTopEdgeTreatment",
- "android/support/v7/widget/ActionMenuView": "androidx/appcompat/widget/ActionMenuView",
- "android/support/design/widget/CoordinatorLayout": "androidx/coordinatorlayout/widget/CoordinatorLayout",
- "android/support/design/widget/FloatingActionButton": "android/support/design/widget/FloatingActionButton",
- "android/support/v7/widget/Toolbar": "androidx/appcompat/widget/Toolbar",
- "android/support/design/bottomappbar/R": "android/support/design/bottomappbar/R",
- "android/arch/paging/AsyncPagedListDiffer": "androidx/paging/AsyncPagedListDiffer",
- "android/arch/paging/PagedList": "androidx/paging/PagedList",
- "android/support/v7/util/ListUpdateCallback": "androidx/recyclerview/widget/ListUpdateCallback",
- "android/support/v7/util/DiffUtil": "androidx/recyclerview/widget/DiffUtil",
- "android/arch/paging/PagedStorage": "androidx/paging/PagedStorage",
"android/support/v7/recyclerview/extensions/AsyncDifferConfig": "androidx/recyclerview/widget/AsyncDifferConfig",
- "android/arch/paging/PagedStorageDiffHelper": "androidx/paging/PagedStorageDiffHelper",
+ "android/support/v7/util/DiffUtil": "androidx/recyclerview/widget/DiffUtil",
+ "android/support/v7/recyclerview/extensions/AsyncListDiffer": "androidx/recyclerview/widget/AsyncListDiffer",
+ "android/support/v7/widget/RecyclerView": "androidx/recyclerview/widget/RecyclerView",
+ "android/support/v7/util/ListUpdateCallback": "androidx/recyclerview/widget/ListUpdateCallback",
"android/support/v7/util/AdapterListUpdateCallback": "androidx/recyclerview/widget/AdapterListUpdateCallback",
- "android/arch/paging/LivePagedListBuilder": "androidx/paging/LivePagedListBuilder",
- "android/arch/paging/DataSource": "androidx/paging/DataSource",
- "android/arch/lifecycle/ComputableLiveData": "androidx/lifecycle/ComputableLiveData",
- "android/arch/paging/LivePagedListProvider": "androidx/paging/LivePagedListProvider",
- "android/arch/paging/PagedListAdapter": "androidx/paging/PagedListAdapter",
- "android/support/design/chip/Chip": "android/support/design/chip/Chip",
- "android/support/design/chip/ChipDrawable": "android/support/design/chip/ChipDrawable",
- "android/support/v4/widget/ExploreByTouchHelper": "androidx/customview/widget/ExploreByTouchHelper",
- "android/support/design/chip/R": "android/support/design/chip/R",
- "android/support/v7/widget/AppCompatCheckBox": "androidx/appcompat/widget/AppCompatCheckBox",
- "android/support/design/animation/MotionSpec": "android/support/design/animation/MotionSpec",
- "android/support/design/canvas/CanvasCompat": "android/support/design/canvas/CanvasCompat",
- "android/support/v4/text/BidiFormatter": "androidx/core/text/BidiFormatter",
- "android/support/design/chip/ChipGroup": "android/support/design/chip/ChipGroup",
- "android/support/v4/app/LoaderManager": "androidx/loader/app/LoaderManager",
- "android/support/v4/content/Loader": "androidx/loader/content/Loader",
- "android/arch/lifecycle/ViewModelStoreOwner": "androidx/lifecycle/ViewModelStoreOwner",
- "android/support/v4/app/LoaderManagerImpl": "androidx/loader/app/LoaderManagerImpl",
- "android/arch/lifecycle/ViewModelStore": "androidx/lifecycle/ViewModelStore",
- "android/arch/lifecycle/MutableLiveData": "androidx/lifecycle/MutableLiveData",
- "android/support/v4/util/DebugUtils": "androidx/core/util/DebugUtils",
- "android/arch/lifecycle/ViewModelProvider": "androidx/lifecycle/ViewModelProvider",
- "android/arch/lifecycle/ViewModel": "androidx/lifecycle/ViewModel",
- "android/support/v4/content/AsyncTaskLoader": "androidx/loader/content/AsyncTaskLoader",
- "android/support/v4/content/ModernAsyncTask": "androidx/loader/content/ModernAsyncTask",
- "android/support/v4/os/OperationCanceledException": "androidx/core/os/OperationCanceledException",
- "android/support/v4/util/TimeUtils": "androidx/core/util/TimeUtils",
- "android/support/v4/content/CursorLoader": "androidx/loader/content/CursorLoader",
- "android/support/v4/os/CancellationSignal": "androidx/core/os/CancellationSignal",
- "android/support/v4/content/ContentResolverCompat": "androidx/core/content/ContentResolverCompat",
- "android/arch/persistence/room/migration/bundle/DatabaseBundle": "androidx/room/migration/bundle/DatabaseBundle",
- "android/arch/persistence/room/migration/bundle/SchemaEquality": "androidx/room/migration/bundle/SchemaEquality",
- "android/arch/persistence/room/migration/bundle/EntityBundle": "androidx/room/migration/bundle/EntityBundle",
- "android/arch/persistence/room/migration/bundle/SchemaEqualityUtil": "androidx/room/migration/bundle/SchemaEqualityUtil",
- "android/arch/persistence/room/migration/bundle/FieldBundle": "androidx/room/migration/bundle/FieldBundle",
- "android/arch/persistence/room/migration/bundle/IndexBundle": "androidx/room/migration/bundle/IndexBundle",
- "android/arch/persistence/room/migration/bundle/BundleUtil": "androidx/room/migration/bundle/BundleUtil",
- "android/arch/persistence/room/migration/bundle/PrimaryKeyBundle": "androidx/room/migration/bundle/PrimaryKeyBundle",
- "android/arch/persistence/room/migration/bundle/ForeignKeyBundle": "androidx/room/migration/bundle/ForeignKeyBundle",
- "android/arch/persistence/room/migration/bundle/SchemaBundle": "androidx/room/migration/bundle/SchemaBundle",
- "android/support/design/widget/AppBarLayout": "android/support/design/widget/AppBarLayout",
- "android/support/v4/view/OnApplyWindowInsetsListener": "androidx/core/view/OnApplyWindowInsetsListener",
- "android/support/v4/view/WindowInsetsCompat": "androidx/core/view/WindowInsetsCompat",
- "android/support/design/widget/HeaderBehavior": "android/support/design/widget/HeaderBehavior",
- "android/support/design/animation/AnimationUtils": "android/support/design/animation/AnimationUtils",
- "android/support/design/widget/MathUtils": "android/support/design/widget/MathUtils",
- "android/support/design/widget/R": "android/support/design/widget/R",
- "android/support/design/widget/HeaderScrollingViewBehavior": "android/support/design/widget/HeaderScrollingViewBehavior",
- "android/support/design/widget/ViewUtilsLollipop": "android/support/design/widget/ViewUtilsLollipop",
- "android/support/v4/util/ObjectsCompat": "androidx/core/util/ObjectsCompat",
- "android/support/design/widget/BaseTransientBottomBar": "android/support/design/widget/BaseTransientBottomBar",
- "android/support/design/snackbar/ContentViewCallback": "android/support/design/snackbar/ContentViewCallback",
- "android/support/design/widget/SnackbarManager": "android/support/design/widget/SnackbarManager",
- "android/support/design/widget/SwipeDismissBehavior": "android/support/design/widget/SwipeDismissBehavior",
- "android/support/design/widget/BottomNavigationView": "android/support/design/widget/BottomNavigationView",
- "android/support/v7/view/menu/MenuBuilder": "androidx/appcompat/view/menu/MenuBuilder",
- "android/support/v7/view/menu/MenuPresenter": "androidx/appcompat/view/menu/MenuPresenter",
- "android/support/v7/widget/TintTypedArray": "androidx/appcompat/widget/TintTypedArray",
- "android/support/v7/view/SupportMenuInflater": "androidx/appcompat/view/SupportMenuInflater",
- "android/support/design/widget/BottomSheetBehavior": "android/support/design/widget/BottomSheetBehavior",
- "android/support/design/widget/BottomSheetDialog": "android/support/design/widget/BottomSheetDialog",
- "android/support/v7/app/AppCompatDialog": "androidx/appcompat/app/AppCompatDialog",
- "android/support/design/widget/BottomSheetDialogFragment": "android/support/design/widget/BottomSheetDialogFragment",
- "android/support/v7/app/AppCompatDialogFragment": "androidx/appcompat/app/AppCompatDialogFragment",
- "android/support/design/widget/CheckableImageButton": "android/support/design/widget/CheckableImageButton",
- "android/support/v7/widget/AppCompatImageButton": "androidx/appcompat/widget/AppCompatImageButton",
- "android/support/v7/appcompat/R": "androidx/appcompat/R",
- "android/support/design/widget/CircularBorderDrawable": "android/support/design/widget/CircularBorderDrawable",
- "android/support/design/widget/CircularBorderDrawableLollipop": "android/support/design/widget/CircularBorderDrawableLollipop",
- "android/support/design/widget/CollapsingTextHelper": "android/support/design/widget/CollapsingTextHelper",
- "android/support/v4/text/TextDirectionHeuristicsCompat": "androidx/core/text/TextDirectionHeuristicsCompat",
- "android/support/v4/text/TextDirectionHeuristicCompat": "androidx/core/text/TextDirectionHeuristicCompat",
- "android/support/design/widget/CollapsingToolbarLayout": "android/support/design/widget/CollapsingToolbarLayout",
- "android/support/design/widget/ViewOffsetHelper": "android/support/design/widget/ViewOffsetHelper",
- "android/support/design/widget/DescendantOffsetUtils": "android/support/design/widget/DescendantOffsetUtils",
- "android/support/design/widget/CutoutDrawable": "android/support/design/widget/CutoutDrawable",
- "android/support/design/widget/DrawableUtils": "android/support/design/widget/DrawableUtils",
- "android/support/design/widget/FloatingActionButtonImpl": "android/support/design/widget/FloatingActionButtonImpl",
- "android/support/design/widget/ShadowViewDelegate": "android/support/design/widget/ShadowViewDelegate",
- "android/support/design/widget/VisibilityAwareImageButton": "android/support/design/widget/VisibilityAwareImageButton",
- "android/support/v4/view/TintableBackgroundView": "androidx/core/view/TintableBackgroundView",
- "android/support/v4/widget/TintableImageSourceView": "androidx/core/widget/TintableImageSourceView",
- "android/support/design/expandable/ExpandableTransformationWidget": "android/support/design/expandable/ExpandableTransformationWidget",
- "android/support/v7/widget/AppCompatImageHelper": "androidx/appcompat/widget/AppCompatImageHelper",
- "android/support/design/expandable/ExpandableWidgetHelper": "android/support/design/expandable/ExpandableWidgetHelper",
- "android/support/design/expandable/ExpandableWidget": "android/support/design/expandable/ExpandableWidget",
- "android/support/v7/widget/AppCompatDrawableManager": "androidx/appcompat/widget/AppCompatDrawableManager",
- "android/support/design/widget/FloatingActionButtonImplLollipop": "android/support/design/widget/FloatingActionButtonImplLollipop",
- "android/support/design/widget/ShadowDrawableWrapper": "android/support/design/widget/ShadowDrawableWrapper",
- "android/support/design/widget/StateListAnimator": "android/support/design/widget/StateListAnimator",
- "android/support/design/animation/MotionTiming": "android/support/design/animation/MotionTiming",
- "android/support/design/animation/ImageMatrixProperty": "android/support/design/animation/ImageMatrixProperty",
- "android/support/design/animation/MatrixEvaluator": "android/support/design/animation/MatrixEvaluator",
- "android/support/design/animation/AnimatorSetCompat": "android/support/design/animation/AnimatorSetCompat",
- "android/support/design/widget/ViewOffsetBehavior": "android/support/design/widget/ViewOffsetBehavior",
- "android/support/design/widget/HideBottomViewOnScrollBehavior": "android/support/design/widget/HideBottomViewOnScrollBehavior",
- "android/support/design/widget/IndicatorViewController": "android/support/design/widget/IndicatorViewController",
- "android/support/design/widget/TextInputLayout": "android/support/design/widget/TextInputLayout",
- "android/support/v7/widget/AppCompatTextView": "androidx/appcompat/widget/AppCompatTextView",
- "android/support/v4/widget/TextViewCompat": "androidx/core/widget/TextViewCompat",
- "android/support/design/widget/NavigationView": "android/support/design/widget/NavigationView",
- "android/support/v7/view/menu/MenuView": "androidx/appcompat/view/menu/MenuView",
- "android/support/v7/view/menu/MenuItemImpl": "androidx/appcompat/view/menu/MenuItemImpl",
- "android/support/v7/graphics/drawable/DrawableWrapper": "androidx/appcompat/graphics/drawable/DrawableWrapper",
- "android/support/design/widget/Snackbar": "android/support/design/widget/Snackbar",
- "android/support/design/widget/TabItem": "android/support/design/widget/TabItem",
- "android/support/design/widget/TabLayout": "android/support/design/widget/TabLayout",
- "android/support/v4/view/ViewPager": "androidx/viewpager/widget/ViewPager",
- "android/support/v4/view/PagerAdapter": "androidx/viewpager/widget/PagerAdapter",
- "android/support/v7/app/ActionBar": "androidx/appcompat/app/ActionBar",
- "android/support/v4/view/PointerIconCompat": "androidx/core/view/PointerIconCompat",
- "android/support/v4/view/MarginLayoutParamsCompat": "androidx/core/view/MarginLayoutParamsCompat",
- "android/support/v7/widget/TooltipCompat": "androidx/appcompat/widget/TooltipCompat",
+ "android/support/v7/recyclerview/extensions/ListAdapter": "androidx/recyclerview/widget/ListAdapter",
+ "android/support/v7/util/AsyncListUtil": "androidx/recyclerview/widget/AsyncListUtil",
+ "android/support/v7/util/ThreadUtil": "androidx/recyclerview/widget/ThreadUtil",
+ "android/support/v7/util/TileList": "androidx/recyclerview/widget/TileList",
+ "android/support/annotation/WorkerThread": "androidx/annotation/WorkerThread",
+ "android/support/annotation/UiThread": "androidx/annotation/UiThread",
+ "android/support/v7/util/MessageThreadUtil": "androidx/recyclerview/widget/MessageThreadUtil",
+ "android/support/v7/util/BatchingListUpdateCallback": "androidx/recyclerview/widget/BatchingListUpdateCallback",
+ "android/support/annotation/VisibleForTesting": "androidx/annotation/VisibleForTesting",
+ "android/support/v7/util/SortedList": "androidx/recyclerview/widget/SortedList",
+ "android/support/v7/widget/AdapterHelper": "androidx/recyclerview/widget/AdapterHelper",
+ "android/support/v7/widget/OpReorderer": "androidx/recyclerview/widget/OpReorderer",
"android/support/v4/util/Pools": "androidx/core/util/Pools",
- "android/support/design/widget/TextInputEditText": "android/support/design/widget/TextInputEditText",
- "android/support/v7/widget/AppCompatEditText": "androidx/appcompat/widget/AppCompatEditText",
- "android/support/v7/widget/DrawableUtils": "androidx/appcompat/widget/DrawableUtils",
- "android/support/design/bottomnavigation/LabelVisibilityMode": "android/support/design/bottomnavigation/LabelVisibilityMode",
- "android/support/design/button/MaterialButton": "android/support/design/button/MaterialButton",
- "android/support/v7/widget/AppCompatButton": "androidx/appcompat/widget/AppCompatButton",
- "android/support/design/button/R": "android/support/design/button/R",
- "android/support/design/button/MaterialButtonHelper": "android/support/design/button/MaterialButtonHelper",
- "android/support/design/button/MaterialButtonBackgroundDrawable": "android/support/design/button/MaterialButtonBackgroundDrawable",
- "android/support/v4/view/animation/FastOutLinearInInterpolator": "androidx/interpolator/view/animation/FastOutLinearInInterpolator",
- "android/support/v4/view/animation/LookupTableInterpolator": "androidx/interpolator/view/animation/LookupTableInterpolator",
- "android/support/v4/view/animation/LinearOutSlowInInterpolator": "androidx/interpolator/view/animation/LinearOutSlowInInterpolator",
- "android/arch/lifecycle/MediatorLiveData": "androidx/lifecycle/MediatorLiveData",
- "android/arch/lifecycle/Transformations": "androidx/lifecycle/Transformations",
- "android/arch/core/util/Function": "androidx/arch/core/util/Function",
- "android/databinding/adapters/AbsListViewBindingAdapter": "androidx/databinding/adapters/AbsListViewBindingAdapter",
- "android/databinding/adapters/AbsSeekBarBindingAdapter": "androidx/databinding/adapters/AbsSeekBarBindingAdapter",
- "android/databinding/adapters/AbsSpinnerBindingAdapter": "androidx/databinding/adapters/AbsSpinnerBindingAdapter",
- "android/databinding/adapters/ObservableListAdapter": "androidx/databinding/adapters/ObservableListAdapter",
- "android/databinding/adapters/ActionMenuViewBindingAdapter": "androidx/databinding/adapters/ActionMenuViewBindingAdapter",
- "android/databinding/adapters/AdapterViewBindingAdapter": "androidx/databinding/adapters/AdapterViewBindingAdapter",
- "android/databinding/adapters/AutoCompleteTextViewBindingAdapter": "androidx/databinding/adapters/AutoCompleteTextViewBindingAdapter",
- "android/databinding/adapters/CalendarViewBindingAdapter": "androidx/databinding/adapters/CalendarViewBindingAdapter",
- "android/databinding/adapters/CardViewBindingAdapter": "androidx/databinding/adapters/CardViewBindingAdapter",
- "android/databinding/adapters/CheckedTextViewBindingAdapter": "androidx/databinding/adapters/CheckedTextViewBindingAdapter",
- "android/databinding/adapters/ChronometerBindingAdapter": "androidx/databinding/adapters/ChronometerBindingAdapter",
- "android/databinding/adapters/CompoundButtonBindingAdapter": "androidx/databinding/adapters/CompoundButtonBindingAdapter",
- "android/databinding/adapters/Converters": "androidx/databinding/adapters/Converters",
- "android/databinding/adapters/DatePickerBindingAdapter": "androidx/databinding/adapters/DatePickerBindingAdapter",
- "android/databinding/adapters/ListenerUtil": "androidx/databinding/adapters/ListenerUtil",
- "android/databinding/adapters/ExpandableListViewBindingAdapter": "androidx/databinding/adapters/ExpandableListViewBindingAdapter",
- "android/databinding/adapters/FrameLayoutBindingAdapter": "androidx/databinding/adapters/FrameLayoutBindingAdapter",
- "android/databinding/adapters/ImageViewBindingAdapter": "androidx/databinding/adapters/ImageViewBindingAdapter",
- "android/databinding/adapters/LinearLayoutBindingAdapter": "androidx/databinding/adapters/LinearLayoutBindingAdapter",
- "android/databinding/adapters/NumberPickerBindingAdapter": "androidx/databinding/adapters/NumberPickerBindingAdapter",
- "android/databinding/adapters/ProgressBarBindingAdapter": "androidx/databinding/adapters/ProgressBarBindingAdapter",
- "android/databinding/adapters/RadioGroupBindingAdapter": "androidx/databinding/adapters/RadioGroupBindingAdapter",
- "android/databinding/adapters/RatingBarBindingAdapter": "androidx/databinding/adapters/RatingBarBindingAdapter",
- "android/databinding/adapters/SearchViewBindingAdapter": "androidx/databinding/adapters/SearchViewBindingAdapter",
- "android/databinding/adapters/SeekBarBindingAdapter": "androidx/databinding/adapters/SeekBarBindingAdapter",
- "android/databinding/adapters/SpinnerBindingAdapter": "androidx/databinding/adapters/SpinnerBindingAdapter",
- "android/databinding/adapters/SwitchBindingAdapter": "androidx/databinding/adapters/SwitchBindingAdapter",
- "android/databinding/adapters/SwitchCompatBindingAdapter": "androidx/databinding/adapters/SwitchCompatBindingAdapter",
- "android/support/v7/widget/SwitchCompat": "androidx/appcompat/widget/SwitchCompat",
- "android/databinding/adapters/TabHostBindingAdapter": "androidx/databinding/adapters/TabHostBindingAdapter",
- "android/databinding/adapters/TabWidgetBindingAdapter": "androidx/databinding/adapters/TabWidgetBindingAdapter",
- "android/databinding/adapters/TableLayoutBindingAdapter": "androidx/databinding/adapters/TableLayoutBindingAdapter",
- "android/databinding/adapters/TextViewBindingAdapter": "androidx/databinding/adapters/TextViewBindingAdapter",
- "android/databinding/adapters/TimePickerBindingAdapter": "androidx/databinding/adapters/TimePickerBindingAdapter",
- "android/databinding/adapters/ToolbarBindingAdapter": "androidx/databinding/adapters/ToolbarBindingAdapter",
- "android/databinding/adapters/VideoViewBindingAdapter": "androidx/databinding/adapters/VideoViewBindingAdapter",
- "android/databinding/adapters/ViewBindingAdapter": "androidx/databinding/adapters/ViewBindingAdapter",
- "android/databinding/adapters/ViewGroupBindingAdapter": "androidx/databinding/adapters/ViewGroupBindingAdapter",
- "android/databinding/adapters/ViewStubBindingAdapter": "androidx/databinding/adapters/ViewStubBindingAdapter",
- "android/databinding/ViewStubProxy": "androidx/databinding/ViewStubProxy",
- "android/databinding/adapters/ZoomControlsBindingAdapter": "androidx/databinding/adapters/ZoomControlsBindingAdapter",
+ "android/support/v7/widget/ChildHelper": "androidx/recyclerview/widget/ChildHelper",
+ "android/support/v7/widget/DefaultItemAnimator": "androidx/recyclerview/widget/DefaultItemAnimator",
+ "android/support/v7/widget/SimpleItemAnimator": "androidx/recyclerview/widget/SimpleItemAnimator",
+ "android/support/v7/widget/DividerItemDecoration": "androidx/recyclerview/widget/DividerItemDecoration",
+ "android/support/v7/widget/FastScroller": "androidx/recyclerview/widget/FastScroller",
+ "android/support/v7/widget/GapWorker": "androidx/recyclerview/widget/GapWorker",
+ "android/support/v4/os/TraceCompat": "androidx/core/os/TraceCompat",
+ "android/support/v7/widget/GridLayoutManager": "androidx/recyclerview/widget/GridLayoutManager",
+ "android/support/v7/widget/LinearLayoutManager": "androidx/recyclerview/widget/LinearLayoutManager",
+ "android/support/v7/widget/OrientationHelper": "androidx/recyclerview/widget/OrientationHelper",
+ "android/support/v7/widget/LayoutState": "androidx/recyclerview/widget/LayoutState",
+ "android/support/v7/widget/helper/ItemTouchHelper": "androidx/recyclerview/widget/ItemTouchHelper",
+ "android/support/v7/widget/LinearSmoothScroller": "androidx/recyclerview/widget/LinearSmoothScroller",
+ "android/support/v7/widget/ScrollbarHelper": "androidx/recyclerview/widget/ScrollbarHelper",
+ "android/support/v7/widget/ViewBoundsCheck": "androidx/recyclerview/widget/ViewBoundsCheck",
+ "android/support/v7/widget/LinearSnapHelper": "androidx/recyclerview/widget/LinearSnapHelper",
+ "android/support/v7/widget/SnapHelper": "androidx/recyclerview/widget/SnapHelper",
+ "android/support/v7/widget/PagerSnapHelper": "androidx/recyclerview/widget/PagerSnapHelper",
+ "android/support/v7/widget/PositionMap": "androidx/recyclerview/widget/PositionMap",
+ "android/support/v7/widget/ViewInfoStore": "androidx/recyclerview/widget/ViewInfoStore",
+ "android/support/v7/recyclerview/R": "androidx/recyclerview/R",
+ "android/support/annotation/CallSuper": "androidx/annotation/CallSuper",
+ "android/support/v7/widget/RecyclerViewAccessibilityDelegate": "androidx/recyclerview/widget/RecyclerViewAccessibilityDelegate",
+ "android/support/v4/view/ScrollingView": "androidx/core/view/ScrollingView",
+ "android/support/v4/view/NestedScrollingChild2": "androidx/core/view/NestedScrollingChild2",
+ "android/support/v4/view/NestedScrollingChildHelper": "androidx/core/view/NestedScrollingChildHelper",
+ "android/support/v4/view/ViewConfigurationCompat": "androidx/core/view/ViewConfigurationCompat",
+ "android/support/v4/view/MotionEventCompat": "androidx/core/view/MotionEventCompat",
+ "android/support/v4/widget/EdgeEffectCompat": "androidx/core/widget/EdgeEffectCompat",
+ "android/support/v4/util/Preconditions": "androidx/core/util/Preconditions",
+ "android/support/v4/view/accessibility/AccessibilityEventCompat": "androidx/core/view/accessibility/AccessibilityEventCompat",
+ "android/support/v7/widget/StaggeredGridLayoutManager": "androidx/recyclerview/widget/StaggeredGridLayoutManager",
+ "android/support/v4/util/LongSparseArray": "androidx/collection/LongSparseArray",
+ "android/support/v4/view/GestureDetectorCompat": "androidx/core/view/GestureDetectorCompat",
+ "android/support/v7/widget/helper/ItemTouchUIUtilImpl": "androidx/recyclerview/widget/ItemTouchUIUtilImpl",
+ "android/support/v7/widget/helper/ItemTouchUIUtil": "androidx/recyclerview/widget/ItemTouchUIUtil",
+ "android/support/v7/widget/util/SortedListAdapterCallback": "androidx/recyclerview/widget/SortedListAdapterCallback",
+ "android/support/v4/print/PrintHelper": "androidx/print/PrintHelper",
+ "android/databinding/BaseObservable": "androidx/databinding/BaseObservable",
+ "android/databinding/Observable": "androidx/databinding/Observable",
+ "android/databinding/PropertyChangeRegistry": "androidx/databinding/PropertyChangeRegistry",
+ "android/databinding/BaseObservableField": "androidx/databinding/BaseObservableField",
"android/databinding/DataBinderMapper": "androidx/databinding/DataBinderMapper",
"android/databinding/DataBindingComponent": "androidx/databinding/DataBindingComponent",
"android/databinding/ViewDataBinding": "androidx/databinding/ViewDataBinding",
- "android/support/text/emoji/EmojiProcessor": "androidx/emoji/text/EmojiProcessor",
- "android/support/text/emoji/EmojiMetadata": "androidx/emoji/text/EmojiMetadata",
- "android/support/text/emoji/EmojiSpan": "androidx/emoji/text/EmojiSpan",
- "android/support/text/emoji/TypefaceEmojiSpan": "androidx/emoji/text/TypefaceEmojiSpan",
- "android/support/v4/graphics/PaintCompat": "androidx/core/graphics/PaintCompat",
- "android/support/text/emoji/widget/SpannableBuilder": "androidx/emoji/widget/SpannableBuilder",
- "android/support/text/emoji/FontRequestEmojiCompatConfig": "androidx/emoji/text/FontRequestEmojiCompatConfig",
- "android/support/v4/provider/FontsContractCompat": "androidx/core/provider/FontsContractCompat",
- "android/support/v4/provider/FontRequest": "androidx/core/provider/FontRequest",
- "android/support/v4/graphics/TypefaceCompatUtil": "androidx/core/graphics/TypefaceCompatUtil",
- "android/support/text/emoji/MetadataListReader": "androidx/emoji/text/MetadataListReader",
- "android/support/text/emoji/widget/EditTextAttributeHelper": "androidx/emoji/widget/EditTextAttributeHelper",
- "android/support/text/emoji/R": "androidx/emoji/R",
- "android/support/text/emoji/widget/EmojiButton": "androidx/emoji/widget/EmojiButton",
- "android/support/text/emoji/widget/EmojiTextViewHelper": "androidx/emoji/widget/EmojiTextViewHelper",
- "android/support/text/emoji/widget/EmojiEditText": "androidx/emoji/widget/EmojiEditText",
- "android/support/text/emoji/widget/EmojiEditTextHelper": "androidx/emoji/widget/EmojiEditTextHelper",
- "android/support/text/emoji/widget/EmojiTextWatcher": "androidx/emoji/widget/EmojiTextWatcher",
- "android/support/text/emoji/widget/EmojiEditableFactory": "androidx/emoji/widget/EmojiEditableFactory",
- "android/support/text/emoji/widget/EmojiKeyListener": "androidx/emoji/widget/EmojiKeyListener",
- "android/support/text/emoji/widget/EmojiInputConnection": "androidx/emoji/widget/EmojiInputConnection",
- "android/support/text/emoji/widget/EmojiExtractEditText": "androidx/emoji/widget/EmojiExtractEditText",
- "android/support/text/emoji/widget/EmojiExtractTextLayout": "androidx/emoji/widget/EmojiExtractTextLayout",
- "android/support/text/emoji/widget/ExtractButtonCompat": "androidx/emoji/widget/ExtractButtonCompat",
- "android/support/text/emoji/widget/EmojiInputFilter": "androidx/emoji/widget/EmojiInputFilter",
- "android/support/text/emoji/widget/EmojiTextView": "androidx/emoji/widget/EmojiTextView",
- "android/support/text/emoji/widget/EmojiTransformationMethod": "androidx/emoji/widget/EmojiTransformationMethod",
- "android/arch/lifecycle/GenericLifecycleObserver": "androidx/lifecycle/GenericLifecycleObserver",
- "android/support/v13/view/DragAndDropPermissionsCompat": "androidx/core/view/DragAndDropPermissionsCompat",
- "android/support/v13/view/DragStartHelper": "androidx/core/view/DragStartHelper",
- "android/support/v4/view/MotionEventCompat": "androidx/core/view/MotionEventCompat",
- "android/support/v13/view/inputmethod/EditorInfoCompat": "androidx/core/view/inputmethod/EditorInfoCompat",
- "android/support/v13/view/inputmethod/InputConnectionCompat": "androidx/core/view/inputmethod/InputConnectionCompat",
- "android/support/v13/view/inputmethod/InputContentInfoCompat": "androidx/core/view/inputmethod/InputContentInfoCompat",
- "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": "androidx/core/accessibilityservice/AccessibilityServiceInfoCompat",
- "android/support/v4/app/ActivityCompat": "androidx/core/app/ActivityCompat",
- "android/support/v4/app/SharedElementCallback": "androidx/core/app/SharedElementCallback",
- "android/support/v4/app/ActivityOptionsCompat": "androidx/core/app/ActivityOptionsCompat",
- "android/support/v4/app/AlarmManagerCompat": "androidx/core/app/AlarmManagerCompat",
- "android/support/v4/app/AppLaunchChecker": "androidx/core/app/AppLaunchChecker",
- "android/support/v4/app/AppOpsManagerCompat": "androidx/core/app/AppOpsManagerCompat",
- "android/support/v4/app/FrameMetricsAggregator": "androidx/core/app/FrameMetricsAggregator",
- "android/support/v4/app/INotificationSideChannel": "androidx/core/app/INotificationSideChannel",
- "android/support/v4/app/JobIntentService": "androidx/core/app/JobIntentService",
- "android/support/v4/app/NavUtils": "androidx/core/app/NavUtils",
- "android/support/v4/app/RemoteInput": "androidx/core/app/RemoteInput",
- "android/support/v4/app/NotificationCompatBuilder": "androidx/core/app/NotificationCompatBuilder",
- "android/support/compat/R": "androidx/core/R",
- "android/support/v4/app/NotificationCompatJellybean": "androidx/core/app/NotificationCompatJellybean",
- "android/support/v4/app/NotificationCompatExtras": "androidx/core/app/NotificationCompatExtras",
- "android/support/v4/app/NotificationCompatSideChannelService": "androidx/core/app/NotificationCompatSideChannelService",
- "android/support/v4/app/NotificationManagerCompat": "androidx/core/app/NotificationManagerCompat",
- "android/support/v4/app/ServiceCompat": "androidx/core/app/ServiceCompat",
- "android/support/v4/app/ShareCompat": "androidx/core/app/ShareCompat",
- "android/arch/lifecycle/LifecycleRegistry": "androidx/lifecycle/LifecycleRegistry",
- "android/arch/lifecycle/ReportFragment": "androidx/lifecycle/ReportFragment",
- "android/support/v4/app/TaskStackBuilder": "androidx/core/app/TaskStackBuilder",
- "android/support/v4/content/FileProvider": "androidx/core/content/FileProvider",
- "android/support/v4/content/IntentCompat": "androidx/core/content/IntentCompat",
- "android/support/v4/content/MimeTypeFilter": "androidx/core/content/MimeTypeFilter",
- "android/support/v4/content/PermissionChecker": "androidx/core/content/PermissionChecker",
- "android/support/v4/content/SharedPreferencesCompat": "androidx/core/content/SharedPreferencesCompat",
- "android/support/v4/content/pm/ActivityInfoCompat": "androidx/core/content/pm/ActivityInfoCompat",
- "android/support/v4/content/pm/ShortcutInfoCompat": "androidx/core/content/pm/ShortcutInfoCompat",
- "android/support/v4/graphics/drawable/IconCompat": "androidx/core/graphics/drawable/IconCompat",
- "android/support/v4/content/pm/ShortcutManagerCompat": "androidx/core/content/pm/ShortcutManagerCompat",
- "android/support/v4/content/res/ConfigurationHelper": "androidx/core/content/res/ConfigurationHelper",
- "android/support/v4/content/res/FontResourcesParserCompat": "androidx/core/content/res/FontResourcesParserCompat",
- "android/support/v4/graphics/TypefaceCompat": "androidx/core/graphics/TypefaceCompat",
- "android/support/v4/content/res/TypedArrayUtils": "androidx/core/content/res/TypedArrayUtils",
- "android/support/v4/database/DatabaseUtilsCompat": "androidx/core/database/DatabaseUtilsCompat",
- "android/support/v4/graphics/BitmapCompat": "androidx/core/graphics/BitmapCompat",
- "android/support/v4/graphics/PathParser": "androidx/core/graphics/PathParser",
- "android/support/v4/util/LruCache": "androidx/collection/LruCache",
- "android/support/v4/graphics/TypefaceCompatApi28Impl": "androidx/core/graphics/TypefaceCompatApi28Impl",
- "android/support/v4/graphics/TypefaceCompatApi26Impl": "androidx/core/graphics/TypefaceCompatApi26Impl",
- "android/support/v4/graphics/TypefaceCompatApi24Impl": "androidx/core/graphics/TypefaceCompatApi24Impl",
- "android/support/v4/graphics/TypefaceCompatApi21Impl": "androidx/core/graphics/TypefaceCompatApi21Impl",
- "android/support/v4/graphics/TypefaceCompatBaseImpl": "androidx/core/graphics/TypefaceCompatBaseImpl",
- "android/support/v4/graphics/drawable/WrappedDrawable": "androidx/core/graphics/drawable/WrappedDrawable",
- "android/support/v4/graphics/drawable/WrappedDrawableApi21": "androidx/core/graphics/drawable/WrappedDrawableApi21",
- "android/support/v4/graphics/drawable/WrappedDrawableApi19": "androidx/core/graphics/drawable/WrappedDrawableApi19",
- "android/support/v4/graphics/drawable/WrappedDrawableApi14": "androidx/core/graphics/drawable/WrappedDrawableApi14",
- "android/support/v4/graphics/drawable/RoundedBitmapDrawable": "androidx/core/graphics/drawable/RoundedBitmapDrawable",
- "android/support/v4/graphics/drawable/RoundedBitmapDrawable21": "androidx/core/graphics/drawable/RoundedBitmapDrawable21",
- "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": "androidx/core/graphics/drawable/RoundedBitmapDrawableFactory",
- "android/support/v4/hardware/display/DisplayManagerCompat": "androidx/core/hardware/display/DisplayManagerCompat",
- "android/support/v4/hardware/fingerprint/FingerprintManagerCompat": "androidx/core/hardware/fingerprint/FingerprintManagerCompat",
- "android/support/v4/internal/view/SupportMenu": "androidx/core/internal/view/SupportMenu",
- "android/support/v4/internal/view/SupportMenuItem": "androidx/core/internal/view/SupportMenuItem",
- "android/support/v4/view/ActionProvider": "androidx/core/view/ActionProvider",
- "android/support/v4/internal/view/SupportSubMenu": "androidx/core/internal/view/SupportSubMenu",
- "android/support/v4/math/MathUtils": "androidx/core/math/MathUtils",
- "android/support/v4/net/ConnectivityManagerCompat": "androidx/core/net/ConnectivityManagerCompat",
- "android/support/v4/net/DatagramSocketWrapper": "androidx/core/net/DatagramSocketWrapper",
- "android/support/v4/net/TrafficStatsCompat": "androidx/core/net/TrafficStatsCompat",
- "android/support/v4/os/ConfigurationCompat": "androidx/core/os/ConfigurationCompat",
- "android/support/v4/os/LocaleListCompat": "androidx/core/os/LocaleListCompat",
- "android/support/v4/os/EnvironmentCompat": "androidx/core/os/EnvironmentCompat",
- "android/support/v4/os/IResultReceiver": "androidx/core/os/IResultReceiver",
- "android/support/v4/os/LocaleHelper": "androidx/core/os/LocaleHelper",
- "android/support/v4/os/LocaleListInterface": "androidx/core/os/LocaleListInterface",
- "android/support/v4/os/LocaleListHelper": "androidx/core/os/LocaleListHelper",
- "android/support/v4/os/ParcelableCompat": "androidx/core/os/ParcelableCompat",
- "android/support/v4/os/ParcelableCompatCreatorCallbacks": "androidx/core/os/ParcelableCompatCreatorCallbacks",
- "android/support/v4/os/TraceCompat": "androidx/core/os/TraceCompat",
- "android/support/v4/os/UserManagerCompat": "androidx/core/os/UserManagerCompat",
- "android/support/v4/provider/SelfDestructiveThread": "androidx/core/provider/SelfDestructiveThread",
- "android/support/v4/text/TextUtilsCompat": "androidx/core/text/TextUtilsCompat",
- "android/support/v4/text/ICUCompat": "androidx/core/text/ICUCompat",
- "android/support/v4/text/util/FindAddress": "androidx/core/text/util/FindAddress",
- "android/support/v4/text/util/LinkifyCompat": "androidx/core/text/util/LinkifyCompat",
- "android/support/v4/util/PatternsCompat": "androidx/core/util/PatternsCompat",
- "android/support/v4/util/AtomicFile": "androidx/core/util/AtomicFile",
- "android/support/v4/util/LogWriter": "androidx/core/util/LogWriter",
- "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": "androidx/core/view/accessibility/AccessibilityNodeProviderCompat",
- "android/support/v4/view/GestureDetectorCompat": "androidx/core/view/GestureDetectorCompat",
- "android/support/v4/view/InputDeviceCompat": "androidx/core/view/InputDeviceCompat",
- "android/support/v4/view/LayoutInflaterCompat": "androidx/core/view/LayoutInflaterCompat",
- "android/support/v4/view/LayoutInflaterFactory": "androidx/core/view/LayoutInflaterFactory",
- "android/support/v4/view/MenuCompat": "androidx/core/view/MenuCompat",
- "android/support/v4/view/MenuItemCompat": "androidx/core/view/MenuItemCompat",
- "android/support/v4/view/NestedScrollingChild2": "androidx/core/view/NestedScrollingChild2",
- "android/support/v4/view/ViewParentCompat": "androidx/core/view/ViewParentCompat",
- "android/support/v4/view/NestedScrollingParent2": "androidx/core/view/NestedScrollingParent2",
- "android/support/v4/view/ScaleGestureDetectorCompat": "androidx/core/view/ScaleGestureDetectorCompat",
- "android/support/v4/view/ScrollingView": "androidx/core/view/ScrollingView",
- "android/support/v4/view/VelocityTrackerCompat": "androidx/core/view/VelocityTrackerCompat",
- "android/support/v4/view/ViewPropertyAnimatorCompat": "androidx/core/view/ViewPropertyAnimatorCompat",
- "android/support/v4/view/ViewConfigurationCompat": "androidx/core/view/ViewConfigurationCompat",
- "android/support/v4/view/ViewGroupCompat": "androidx/core/view/ViewGroupCompat",
- "android/support/v4/view/ViewPropertyAnimatorListener": "androidx/core/view/ViewPropertyAnimatorListener",
- "android/support/v4/view/ViewPropertyAnimatorUpdateListener": "androidx/core/view/ViewPropertyAnimatorUpdateListener",
- "android/support/v4/view/ViewPropertyAnimatorListenerAdapter": "androidx/core/view/ViewPropertyAnimatorListenerAdapter",
- "android/support/v4/view/WindowCompat": "androidx/core/view/WindowCompat",
- "android/support/v4/view/accessibility/AccessibilityEventCompat": "androidx/core/view/accessibility/AccessibilityEventCompat",
- "android/support/v4/view/accessibility/AccessibilityRecordCompat": "androidx/core/view/accessibility/AccessibilityRecordCompat",
- "android/support/v4/view/accessibility/AccessibilityManagerCompat": "androidx/core/view/accessibility/AccessibilityManagerCompat",
- "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": "androidx/core/view/accessibility/AccessibilityWindowInfoCompat",
- "android/support/v4/view/animation/PathInterpolatorApi14": "androidx/core/view/animation/PathInterpolatorApi14",
- "android/support/v4/view/animation/PathInterpolatorCompat": "androidx/core/view/animation/PathInterpolatorCompat",
- "android/support/v4/widget/AutoScrollHelper": "androidx/core/widget/AutoScrollHelper",
- "android/support/v4/widget/AutoSizeableTextView": "androidx/core/widget/AutoSizeableTextView",
- "android/support/v4/widget/CompoundButtonCompat": "androidx/core/widget/CompoundButtonCompat",
- "android/support/v4/widget/TintableCompoundButton": "androidx/core/widget/TintableCompoundButton",
- "android/support/v4/widget/ContentLoadingProgressBar": "androidx/core/widget/ContentLoadingProgressBar",
- "android/support/v4/widget/EdgeEffectCompat": "androidx/core/widget/EdgeEffectCompat",
- "android/support/v4/widget/ImageViewCompat": "androidx/core/widget/ImageViewCompat",
- "android/support/v4/widget/ListPopupWindowCompat": "androidx/core/widget/ListPopupWindowCompat",
- "android/support/v4/widget/ListViewAutoScrollHelper": "androidx/core/widget/ListViewAutoScrollHelper",
- "android/support/v4/widget/NestedScrollView": "androidx/core/widget/NestedScrollView",
- "android/support/v4/widget/PopupMenuCompat": "androidx/core/widget/PopupMenuCompat",
- "android/support/v4/widget/PopupWindowCompat": "androidx/core/widget/PopupWindowCompat",
- "android/support/v4/widget/ScrollerCompat": "androidx/core/widget/ScrollerCompat",
- "android/arch/core/internal/FastSafeIterableMap": "androidx/arch/core/internal/FastSafeIterableMap",
- "android/arch/lifecycle/LifecycleRegistryOwner": "androidx/lifecycle/LifecycleRegistryOwner",
- "android/support/design/transformation/ExpandableBehavior": "android/support/design/transformation/ExpandableBehavior",
- "android/support/design/transformation/ExpandableTransformationBehavior": "android/support/design/transformation/ExpandableTransformationBehavior",
- "android/support/design/transformation/FabTransformationBehavior": "android/support/design/transformation/FabTransformationBehavior",
- "android/support/design/circularreveal/CircularRevealWidget": "android/support/design/circularreveal/CircularRevealWidget",
- "android/support/design/animation/Positioning": "android/support/design/animation/Positioning",
- "android/support/design/transformation/R": "android/support/design/transformation/R",
- "android/support/design/animation/DrawableAlphaProperty": "android/support/design/animation/DrawableAlphaProperty",
- "android/support/design/math/MathUtils": "android/support/design/math/MathUtils",
- "android/support/design/circularreveal/CircularRevealCompat": "android/support/design/circularreveal/CircularRevealCompat",
- "android/support/design/animation/ArgbEvaluatorCompat": "android/support/design/animation/ArgbEvaluatorCompat",
- "android/support/design/circularreveal/CircularRevealHelper": "android/support/design/circularreveal/CircularRevealHelper",
- "android/support/design/animation/ChildrenAlphaProperty": "android/support/design/animation/ChildrenAlphaProperty",
- "android/support/design/transformation/TransformationChildLayout": "android/support/design/transformation/TransformationChildLayout",
- "android/support/design/transformation/TransformationChildCard": "android/support/design/transformation/TransformationChildCard",
- "android/support/design/transformation/FabTransformationScrimBehavior": "android/support/design/transformation/FabTransformationScrimBehavior",
- "android/support/design/transformation/FabTransformationSheetBehavior": "android/support/design/transformation/FabTransformationSheetBehavior",
- "android/support/design/circularreveal/cardview/CircularRevealCardView": "android/support/design/circularreveal/cardview/CircularRevealCardView",
- "android/support/design/circularreveal/CircularRevealFrameLayout": "android/support/design/circularreveal/CircularRevealFrameLayout",
- "android/support/v4/widget/CursorAdapter": "androidx/cursoradapter/widget/CursorAdapter",
- "android/support/v4/widget/CursorFilter": "androidx/cursoradapter/widget/CursorFilter",
- "android/support/v4/widget/ResourceCursorAdapter": "androidx/cursoradapter/widget/ResourceCursorAdapter",
- "android/support/v4/widget/SimpleCursorAdapter": "androidx/cursoradapter/widget/SimpleCursorAdapter",
- "android/support/design/theme/MaterialComponentsViewInflater": "android/support/design/theme/MaterialComponentsViewInflater",
- "android/support/v7/app/AppCompatViewInflater": "androidx/appcompat/app/AppCompatViewInflater",
- "android/databinding/BaseObservable": "androidx/databinding/BaseObservable",
- "android/databinding/PropertyChangeRegistry": "androidx/databinding/PropertyChangeRegistry",
- "android/databinding/BaseObservableField": "androidx/databinding/BaseObservableField",
"android/databinding/DataBindingUtil": "androidx/databinding/DataBindingUtil",
"android/databinding/DataBinderMapperImpl": "androidx/databinding/DataBinderMapperImpl",
"android/databinding/ListChangeRegistry": "androidx/databinding/ListChangeRegistry",
+ "android/databinding/CallbackRegistry": "androidx/databinding/CallbackRegistry",
+ "android/databinding/ObservableList": "androidx/databinding/ObservableList",
"android/databinding/MapChangeRegistry": "androidx/databinding/MapChangeRegistry",
+ "android/databinding/ObservableMap": "androidx/databinding/ObservableMap",
"android/databinding/MergedDataBinderMapper": "androidx/databinding/MergedDataBinderMapper",
"android/databinding/ObservableArrayList": "androidx/databinding/ObservableArrayList",
"android/databinding/ObservableArrayMap": "androidx/databinding/ObservableArrayMap",
@@ -2879,33 +2405,248 @@
"android/databinding/ObservableParcelable": "androidx/databinding/ObservableParcelable",
"android/databinding/ObservableShort": "androidx/databinding/ObservableShort",
"android/databinding/OnRebindCallback": "androidx/databinding/OnRebindCallback",
- "android/support/v4/util/LongSparseArray": "androidx/collection/LongSparseArray",
- "android/support/v4/app/BackStackRecord": "androidx/fragment/app/BackStackRecord",
- "android/support/v4/app/Fragment": "androidx/fragment/app/Fragment",
- "android/support/v4/app/FragmentTransaction": "androidx/fragment/app/FragmentTransaction",
+ "android/arch/lifecycle/Observer": "androidx/lifecycle/Observer",
+ "android/arch/lifecycle/LiveData": "androidx/lifecycle/LiveData",
+ "android/arch/lifecycle/LifecycleOwner": "androidx/lifecycle/LifecycleOwner",
+ "android/arch/lifecycle/LifecycleObserver": "androidx/lifecycle/LifecycleObserver",
+ "android/arch/lifecycle/Lifecycle": "androidx/lifecycle/Lifecycle",
+ "android/arch/lifecycle/OnLifecycleEvent": "androidx/lifecycle/OnLifecycleEvent",
+ "android/databinding/InverseBindingListener": "androidx/databinding/InverseBindingListener",
+ "android/support/annotation/MainThread": "androidx/annotation/MainThread",
+ "android/databinding/ViewStubProxy": "androidx/databinding/ViewStubProxy",
+ "android/support/v7/widget/CardView": "androidx/cardview/widget/CardView",
+ "android/support/v7/widget/CardViewDelegate": "androidx/cardview/widget/CardViewDelegate",
+ "android/support/v7/cardview/R": "androidx/cardview/R",
+ "android/support/v7/widget/CardViewImpl": "androidx/cardview/widget/CardViewImpl",
+ "android/support/v7/widget/CardViewApi21Impl": "androidx/cardview/widget/CardViewApi21Impl",
+ "android/support/v7/widget/CardViewApi17Impl": "androidx/cardview/widget/CardViewApi17Impl",
+ "android/support/v7/widget/CardViewBaseImpl": "androidx/cardview/widget/CardViewBaseImpl",
+ "android/support/v7/widget/RoundRectDrawableWithShadow": "androidx/cardview/widget/RoundRectDrawableWithShadow",
+ "android/support/v7/widget/RoundRectDrawable": "androidx/cardview/widget/RoundRectDrawable",
+ "android/databinding/BindingAdapter": "androidx/databinding/BindingAdapter",
+ "android/databinding/BindingMethod": "androidx/databinding/BindingMethod",
+ "android/databinding/BindingBuildInfo": "androidx/databinding/BindingBuildInfo",
+ "android/databinding/Untaggable": "androidx/databinding/Untaggable",
+ "android/databinding/InverseBindingMethod": "androidx/databinding/InverseBindingMethod",
+ "android/databinding/BindingMethods": "androidx/databinding/BindingMethods",
+ "android/databinding/BindingConversion": "androidx/databinding/BindingConversion",
+ "android/databinding/InverseBindingMethods": "androidx/databinding/InverseBindingMethods",
+ "android/databinding/InverseMethod": "androidx/databinding/InverseMethod",
+ "android/databinding/Bindable": "androidx/databinding/Bindable",
+ "android/databinding/InverseBindingAdapter": "androidx/databinding/InverseBindingAdapter",
+ "android/support/v7/view/menu/MenuView": "androidx/appcompat/view/menu/MenuView",
+ "android/support/v7/view/menu/MenuItemImpl": "androidx/appcompat/view/menu/MenuItemImpl",
+ "android/support/v7/widget/TooltipCompat": "androidx/appcompat/widget/TooltipCompat",
+ "android/support/v4/view/PointerIconCompat": "androidx/core/view/PointerIconCompat",
+ "android/support/v4/graphics/drawable/DrawableCompat": "androidx/core/graphics/drawable/DrawableCompat",
+ "android/support/annotation/StyleRes": "androidx/annotation/StyleRes",
+ "android/support/v4/widget/TextViewCompat": "androidx/core/widget/TextViewCompat",
+ "android/support/v7/view/menu/MenuBuilder": "androidx/appcompat/view/menu/MenuBuilder",
+ "android/support/v7/view/menu/MenuPresenter": "androidx/appcompat/view/menu/MenuPresenter",
+ "android/support/v7/appcompat/R": "androidx/appcompat/R",
+ "android/support/transition/TransitionSet": "androidx/transition/TransitionSet",
+ "android/support/annotation/Dimension": "androidx/annotation/Dimension",
+ "android/support/transition/AutoTransition": "androidx/transition/AutoTransition",
+ "android/support/v4/view/animation/FastOutSlowInInterpolator": "androidx/interpolator/view/animation/FastOutSlowInInterpolator",
+ "android/support/transition/Transition": "androidx/transition/Transition",
+ "android/support/v7/content/res/AppCompatResources": "androidx/appcompat/content/res/AppCompatResources",
+ "android/support/transition/TransitionManager": "androidx/transition/TransitionManager",
+ "android/support/v7/view/menu/SubMenuBuilder": "androidx/appcompat/view/menu/SubMenuBuilder",
+ "android/support/v7/widget/LinearLayoutCompat": "androidx/appcompat/widget/LinearLayoutCompat",
+ "android/support/v4/content/res/ResourcesCompat": "androidx/core/content/res/ResourcesCompat",
+ "android/support/annotation/LayoutRes": "androidx/annotation/LayoutRes",
+ "android/support/v4/view/WindowInsetsCompat": "androidx/core/view/WindowInsetsCompat",
+ "android/support/v4/view/OnApplyWindowInsetsListener": "androidx/core/view/OnApplyWindowInsetsListener",
+ "android/support/design/snackbar/ContentViewCallback": "android/support/design/snackbar/ContentViewCallback",
+ "android/support/transition/TransitionValues": "androidx/transition/TransitionValues",
+ "android/support/annotation/StyleableRes": "androidx/annotation/StyleableRes",
+ "android/support/annotation/AttrRes": "androidx/annotation/AttrRes",
+ "android/support/v7/widget/TintTypedArray": "androidx/appcompat/widget/TintTypedArray",
+ "android/support/v4/widget/ExploreByTouchHelper": "androidx/customview/widget/ExploreByTouchHelper",
+ "android/support/v4/widget/FocusStrategy": "androidx/customview/widget/FocusStrategy",
+ "android/support/v4/util/SparseArrayCompat": "androidx/collection/SparseArrayCompat",
+ "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": "androidx/core/view/accessibility/AccessibilityNodeProviderCompat",
+ "android/support/v4/view/ViewParentCompat": "androidx/core/view/ViewParentCompat",
+ "android/support/v4/view/accessibility/AccessibilityRecordCompat": "androidx/core/view/accessibility/AccessibilityRecordCompat",
+ "android/arch/persistence/room/migration/bundle/DatabaseBundle": "androidx/room/migration/bundle/DatabaseBundle",
+ "android/arch/persistence/room/migration/bundle/SchemaEquality": "androidx/room/migration/bundle/SchemaEquality",
+ "android/arch/persistence/room/migration/bundle/EntityBundle": "androidx/room/migration/bundle/EntityBundle",
+ "android/arch/persistence/room/migration/bundle/SchemaEqualityUtil": "androidx/room/migration/bundle/SchemaEqualityUtil",
+ "android/arch/persistence/room/migration/bundle/FieldBundle": "androidx/room/migration/bundle/FieldBundle",
+ "android/arch/persistence/room/migration/bundle/IndexBundle": "androidx/room/migration/bundle/IndexBundle",
+ "android/arch/persistence/room/migration/bundle/BundleUtil": "androidx/room/migration/bundle/BundleUtil",
+ "android/arch/persistence/room/migration/bundle/PrimaryKeyBundle": "androidx/room/migration/bundle/PrimaryKeyBundle",
+ "android/arch/persistence/room/migration/bundle/ForeignKeyBundle": "androidx/room/migration/bundle/ForeignKeyBundle",
+ "android/arch/persistence/room/migration/bundle/SchemaBundle": "androidx/room/migration/bundle/SchemaBundle",
+ "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout": "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout",
+ "android/support/v17/preference/BaseLeanbackPreferenceFragment": "androidx/leanback/preference/BaseLeanbackPreferenceFragment",
+ "android/support/v14/preference/PreferenceFragment": "androidx/preference/PreferenceFragment",
+ "android/support/v17/preference/R": "androidx/leanback/preference/R",
+ "android/support/v17/leanback/widget/VerticalGridView": "androidx/leanback/widget/VerticalGridView",
+ "android/support/v7/preference/PreferenceRecyclerViewAccessibilityDelegate": "androidx/preference/PreferenceRecyclerViewAccessibilityDelegate",
+ "android/support/v17/preference/LeanbackListPreferenceDialogFragment": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment",
+ "android/support/v7/preference/DialogPreference": "androidx/preference/DialogPreference",
+ "android/support/v14/preference/MultiSelectListPreference": "androidx/preference/MultiSelectListPreference",
+ "android/support/v7/preference/ListPreference": "androidx/preference/ListPreference",
+ "android/support/v17/preference/LeanbackPreferenceDialogFragment": "androidx/leanback/preference/LeanbackPreferenceDialogFragment",
+ "android/support/v4/util/ArraySet": "androidx/collection/ArraySet",
+ "android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21": "androidx/leanback/preference/LeanbackPreferenceFragmentTransitionHelperApi21",
+ "android/support/v7/preference/Preference": "androidx/preference/Preference",
+ "android/support/v17/preference/LeanbackPreferenceFragment": "androidx/leanback/preference/LeanbackPreferenceFragment",
+ "android/support/v7/preference/PreferenceScreen": "androidx/preference/PreferenceScreen",
+ "android/support/v17/leanback/transition/FadeAndShortSlide": "androidx/leanback/transition/FadeAndShortSlide",
+ "android/support/v17/preference/LeanbackSettingsFragment": "androidx/leanback/preference/LeanbackSettingsFragment",
+ "android/support/v17/preference/LeanbackSettingsRootView": "androidx/leanback/preference/LeanbackSettingsRootView",
+ "android/support/v4/view/animation/FastOutLinearInInterpolator": "androidx/interpolator/view/animation/FastOutLinearInInterpolator",
+ "android/support/v4/view/animation/LookupTableInterpolator": "androidx/interpolator/view/animation/LookupTableInterpolator",
+ "android/support/v4/view/animation/LinearOutSlowInInterpolator": "androidx/interpolator/view/animation/LinearOutSlowInInterpolator",
+ "android/support/v7/app/MediaRouteActionProvider": "androidx/mediarouter/app/MediaRouteActionProvider",
+ "android/support/v7/media/MediaRouter": "androidx/mediarouter/media/MediaRouter",
+ "android/support/v4/view/ActionProvider": "androidx/core/view/ActionProvider",
+ "android/support/v7/media/MediaRouteSelector": "androidx/mediarouter/media/MediaRouteSelector",
+ "android/support/v7/app/MediaRouteDialogFactory": "androidx/mediarouter/app/MediaRouteDialogFactory",
+ "android/support/v7/app/MediaRouteButton": "androidx/mediarouter/app/MediaRouteButton",
+ "android/support/v7/mediarouter/R": "androidx/mediarouter/R",
+ "android/support/v7/app/MediaRouterThemeHelper": "androidx/mediarouter/app/MediaRouterThemeHelper",
"android/support/v4/app/FragmentManager": "androidx/fragment/app/FragmentManager",
- "android/support/v4/app/FragmentManagerImpl": "androidx/fragment/app/FragmentManagerImpl",
- "android/support/v4/app/FragmentHostCallback": "androidx/fragment/app/FragmentHostCallback",
- "android/support/v4/app/FragmentTransition": "androidx/fragment/app/FragmentTransition",
- "android/support/v4/app/BackStackState": "androidx/fragment/app/BackStackState",
- "android/support/v4/app/BaseFragmentActivityApi14": "androidx/fragment/app/BaseFragmentActivityApi14",
- "android/support/v4/app/BaseFragmentActivityApi16": "androidx/fragment/app/BaseFragmentActivityApi16",
- "android/support/v4/app/DialogFragment": "androidx/fragment/app/DialogFragment",
+ "android/support/v4/app/Fragment": "androidx/fragment/app/Fragment",
+ "android/support/v7/app/MediaRouteChooserDialogFragment": "androidx/mediarouter/app/MediaRouteChooserDialogFragment",
+ "android/support/v7/app/MediaRouteControllerDialogFragment": "androidx/mediarouter/app/MediaRouteControllerDialogFragment",
"android/support/v4/app/FragmentActivity": "androidx/fragment/app/FragmentActivity",
- "android/support/v4/app/FragmentContainer": "androidx/fragment/app/FragmentContainer",
- "android/support/v4/app/FragmentManagerNonConfig": "androidx/fragment/app/FragmentManagerNonConfig",
- "android/support/v4/app/SuperNotCalledException": "androidx/fragment/app/SuperNotCalledException",
- "android/support/v4/app/FragmentController": "androidx/fragment/app/FragmentController",
- "android/support/v4/app/FragmentState": "androidx/fragment/app/FragmentState",
- "android/support/v4/app/FragmentManagerState": "androidx/fragment/app/FragmentManagerState",
- "android/support/v4/app/FragmentPagerAdapter": "androidx/fragment/app/FragmentPagerAdapter",
- "android/support/v4/app/FragmentStatePagerAdapter": "androidx/fragment/app/FragmentStatePagerAdapter",
- "android/support/v4/app/FragmentTabHost": "androidx/fragment/app/FragmentTabHost",
- "android/support/v4/app/FragmentTransitionImpl": "androidx/fragment/app/FragmentTransitionImpl",
- "android/support/v4/app/OneShotPreDrawListener": "androidx/fragment/app/OneShotPreDrawListener",
- "android/support/v4/app/FragmentTransitionCompat21": "androidx/fragment/app/FragmentTransitionCompat21",
- "android/support/v4/app/ListFragment": "androidx/fragment/app/ListFragment",
- "android/support/v4/widget/SlidingPaneLayout": "androidx/slidingpanelayout/widget/SlidingPaneLayout",
+ "android/support/v7/app/MediaRouteChooserDialog": "androidx/mediarouter/app/MediaRouteChooserDialog",
+ "android/support/v7/app/AppCompatDialog": "androidx/appcompat/app/AppCompatDialog",
+ "android/support/v7/app/MediaRouteDialogHelper": "androidx/mediarouter/app/MediaRouteDialogHelper",
+ "android/support/v4/app/DialogFragment": "androidx/fragment/app/DialogFragment",
+ "android/support/v7/app/MediaRouteControllerDialog": "androidx/mediarouter/app/MediaRouteControllerDialog",
+ "android/support/v7/app/OverlayListView": "androidx/mediarouter/app/OverlayListView",
+ "android/support/v7/graphics/Palette": "androidx/palette/graphics/Palette",
+ "android/support/v4/util/ObjectsCompat": "androidx/core/util/ObjectsCompat",
+ "android/support/v7/app/MediaRouteVolumeSlider": "androidx/mediarouter/app/MediaRouteVolumeSlider",
+ "android/support/v7/app/AlertDialog": "androidx/appcompat/app/AlertDialog",
+ "android/support/v7/app/MediaRouteExpandCollapseButton": "androidx/mediarouter/app/MediaRouteExpandCollapseButton",
+ "android/support/v7/app/MediaRouteDiscoveryFragment": "androidx/mediarouter/app/MediaRouteDiscoveryFragment",
+ "android/support/v7/widget/AppCompatSeekBar": "androidx/appcompat/widget/AppCompatSeekBar",
+ "android/support/v4/graphics/ColorUtils": "androidx/core/graphics/ColorUtils",
+ "android/support/v7/media/MediaControlIntent": "androidx/mediarouter/media/MediaControlIntent",
+ "android/support/v7/media/MediaItemMetadata": "androidx/mediarouter/media/MediaItemMetadata",
+ "android/support/v7/media/MediaItemStatus": "androidx/mediarouter/media/MediaItemStatus",
+ "android/support/v4/util/TimeUtils": "androidx/core/util/TimeUtils",
+ "android/support/v7/media/MediaRouteDescriptor": "androidx/mediarouter/media/MediaRouteDescriptor",
+ "android/support/v7/media/MediaRouteDiscoveryRequest": "androidx/mediarouter/media/MediaRouteDiscoveryRequest",
+ "android/support/v7/media/MediaRouteProvider": "androidx/mediarouter/media/MediaRouteProvider",
+ "android/support/v7/media/MediaRouteProviderDescriptor": "androidx/mediarouter/media/MediaRouteProviderDescriptor",
+ "android/support/v7/media/MediaRouteProviderProtocol": "androidx/mediarouter/media/MediaRouteProviderProtocol",
+ "android/support/v7/media/MediaRouteProviderService": "androidx/mediarouter/media/MediaRouteProviderService",
+ "android/support/v7/media/SystemMediaRouteProvider": "androidx/mediarouter/media/SystemMediaRouteProvider",
+ "android/support/v7/media/RemoteControlClientCompat": "androidx/mediarouter/media/RemoteControlClientCompat",
+ "android/support/v7/media/RegisteredMediaRouteProviderWatcher": "androidx/mediarouter/media/RegisteredMediaRouteProviderWatcher",
+ "android/support/v4/hardware/display/DisplayManagerCompat": "androidx/core/hardware/display/DisplayManagerCompat",
+ "android/support/v4/app/ActivityManagerCompat": "androidx/core/app/ActivityManagerCompat",
+ "android/support/v7/media/MediaRouterApi24": "androidx/mediarouter/media/MediaRouterApi24",
+ "android/support/v7/media/MediaRouterJellybean": "androidx/mediarouter/media/MediaRouterJellybean",
+ "android/support/v7/media/MediaRouterJellybeanMr1": "androidx/mediarouter/media/MediaRouterJellybeanMr1",
+ "android/support/v7/media/MediaRouterJellybeanMr2": "androidx/mediarouter/media/MediaRouterJellybeanMr2",
+ "android/support/v7/media/MediaSessionStatus": "androidx/mediarouter/media/MediaSessionStatus",
+ "android/support/v7/media/RegisteredMediaRouteProvider": "androidx/mediarouter/media/RegisteredMediaRouteProvider",
+ "android/support/v7/media/RemotePlaybackClient": "androidx/mediarouter/media/RemotePlaybackClient",
+ "android/support/text/emoji/bundled/BundledEmojiCompatConfig": "androidx/emoji/bundled/BundledEmojiCompatConfig",
+ "android/support/text/emoji/EmojiCompat": "androidx/emoji/text/EmojiCompat",
+ "android/support/text/emoji/MetadataRepo": "androidx/emoji/text/MetadataRepo",
+ "android/support/v4/provider/DocumentFile": "androidx/documentfile/provider/DocumentFile",
+ "android/support/v4/provider/RawDocumentFile": "androidx/documentfile/provider/RawDocumentFile",
+ "android/support/v4/provider/SingleDocumentFile": "androidx/documentfile/provider/SingleDocumentFile",
+ "android/support/v4/provider/TreeDocumentFile": "androidx/documentfile/provider/TreeDocumentFile",
+ "android/support/v4/provider/DocumentsContractApi19": "androidx/documentfile/provider/DocumentsContractApi19",
+ "android/support/graphics/drawable/AndroidResources": "androidx/vectordrawable/graphics/drawable/AndroidResources",
+ "android/support/graphics/drawable/VectorDrawableCommon": "androidx/vectordrawable/graphics/drawable/VectorDrawableCommon",
+ "android/support/v4/graphics/drawable/TintAwareDrawable": "androidx/core/graphics/drawable/TintAwareDrawable",
+ "android/support/graphics/drawable/VectorDrawableCompat": "androidx/vectordrawable/graphics/drawable/VectorDrawableCompat",
+ "android/support/v4/graphics/PathParser": "androidx/core/graphics/PathParser",
+ "android/support/v4/content/res/TypedArrayUtils": "androidx/core/content/res/TypedArrayUtils",
+ "android/support/design/card/MaterialCardView": "android/support/design/card/MaterialCardView",
+ "android/support/design/card/R": "android/support/design/card/R",
+ "android/support/design/card/MaterialCardViewHelper": "android/support/design/card/MaterialCardViewHelper",
+ "android/support/v4/os/BuildCompat": "androidx/core/os/BuildCompat",
+ "android/support/design/widget/AppBarLayout": "android/support/design/widget/AppBarLayout",
+ "android/support/design/widget/CoordinatorLayout": "androidx/coordinatorlayout/widget/CoordinatorLayout",
+ "android/support/design/widget/HeaderBehavior": "android/support/design/widget/HeaderBehavior",
+ "android/support/design/animation/AnimationUtils": "android/support/design/animation/AnimationUtils",
+ "android/support/design/widget/MathUtils": "android/support/design/widget/MathUtils",
+ "android/support/design/widget/R": "android/support/design/widget/R",
+ "android/support/design/widget/HeaderScrollingViewBehavior": "android/support/design/widget/HeaderScrollingViewBehavior",
+ "android/support/design/widget/ViewUtilsLollipop": "android/support/design/widget/ViewUtilsLollipop",
+ "android/support/design/widget/BaseTransientBottomBar": "android/support/design/widget/BaseTransientBottomBar",
+ "android/support/design/widget/SnackbarManager": "android/support/design/widget/SnackbarManager",
+ "android/support/design/widget/SwipeDismissBehavior": "android/support/design/widget/SwipeDismissBehavior",
+ "android/support/annotation/IntRange": "androidx/annotation/IntRange",
+ "android/support/design/widget/BottomNavigationView": "android/support/design/widget/BottomNavigationView",
+ "android/support/annotation/DimenRes": "androidx/annotation/DimenRes",
+ "android/support/annotation/IdRes": "androidx/annotation/IdRes",
+ "android/support/annotation/IntegerRes": "androidx/annotation/IntegerRes",
+ "android/support/annotation/BoolRes": "androidx/annotation/BoolRes",
+ "android/support/v7/view/SupportMenuInflater": "androidx/appcompat/view/SupportMenuInflater",
+ "android/support/design/widget/BottomSheetBehavior": "android/support/design/widget/BottomSheetBehavior",
+ "android/support/design/widget/BottomSheetDialog": "android/support/design/widget/BottomSheetDialog",
+ "android/support/design/widget/BottomSheetDialogFragment": "android/support/design/widget/BottomSheetDialogFragment",
+ "android/support/v7/app/AppCompatDialogFragment": "androidx/appcompat/app/AppCompatDialogFragment",
+ "android/support/design/widget/CheckableImageButton": "android/support/design/widget/CheckableImageButton",
+ "android/support/v7/widget/AppCompatImageButton": "androidx/appcompat/widget/AppCompatImageButton",
+ "android/support/design/widget/CircularBorderDrawable": "android/support/design/widget/CircularBorderDrawable",
+ "android/support/design/widget/CircularBorderDrawableLollipop": "android/support/design/widget/CircularBorderDrawableLollipop",
+ "android/support/design/widget/CollapsingTextHelper": "android/support/design/widget/CollapsingTextHelper",
+ "android/support/v4/view/GravityCompat": "androidx/core/view/GravityCompat",
+ "android/support/v4/text/TextDirectionHeuristicsCompat": "androidx/core/text/TextDirectionHeuristicsCompat",
+ "android/support/v4/text/TextDirectionHeuristicCompat": "androidx/core/text/TextDirectionHeuristicCompat",
+ "android/support/design/widget/CollapsingToolbarLayout": "android/support/design/widget/CollapsingToolbarLayout",
+ "android/support/design/widget/ViewOffsetHelper": "android/support/design/widget/ViewOffsetHelper",
+ "android/support/v7/widget/Toolbar": "androidx/appcompat/widget/Toolbar",
+ "android/support/design/widget/DescendantOffsetUtils": "android/support/design/widget/DescendantOffsetUtils",
+ "android/support/design/widget/CutoutDrawable": "android/support/design/widget/CutoutDrawable",
+ "android/support/design/widget/DrawableUtils": "android/support/design/widget/DrawableUtils",
+ "android/support/design/widget/FloatingActionButton": "android/support/design/widget/FloatingActionButton",
+ "android/support/design/widget/FloatingActionButtonImpl": "android/support/design/widget/FloatingActionButtonImpl",
+ "android/support/design/widget/ShadowViewDelegate": "android/support/design/widget/ShadowViewDelegate",
+ "android/support/design/widget/VisibilityAwareImageButton": "android/support/design/widget/VisibilityAwareImageButton",
+ "android/support/v4/view/TintableBackgroundView": "androidx/core/view/TintableBackgroundView",
+ "android/support/v4/widget/TintableImageSourceView": "androidx/core/widget/TintableImageSourceView",
+ "android/support/design/expandable/ExpandableTransformationWidget": "android/support/design/expandable/ExpandableTransformationWidget",
+ "android/support/v7/widget/AppCompatImageHelper": "androidx/appcompat/widget/AppCompatImageHelper",
+ "android/support/design/expandable/ExpandableWidgetHelper": "android/support/design/expandable/ExpandableWidgetHelper",
+ "android/support/design/resources/MaterialResources": "android/support/design/resources/MaterialResources",
+ "android/support/design/animation/MotionSpec": "android/support/design/animation/MotionSpec",
+ "android/support/design/expandable/ExpandableWidget": "android/support/design/expandable/ExpandableWidget",
+ "android/support/v7/widget/AppCompatDrawableManager": "androidx/appcompat/widget/AppCompatDrawableManager",
+ "android/support/design/stateful/ExtendableSavedState": "android/support/design/stateful/ExtendableSavedState",
+ "android/support/v4/util/SimpleArrayMap": "androidx/collection/SimpleArrayMap",
+ "android/support/annotation/AnimatorRes": "androidx/annotation/AnimatorRes",
+ "android/support/design/widget/FloatingActionButtonImplLollipop": "android/support/design/widget/FloatingActionButtonImplLollipop",
+ "android/support/design/widget/ShadowDrawableWrapper": "android/support/design/widget/ShadowDrawableWrapper",
+ "android/support/design/widget/StateListAnimator": "android/support/design/widget/StateListAnimator",
+ "android/support/design/ripple/RippleUtils": "android/support/design/ripple/RippleUtils",
+ "android/support/design/animation/MotionTiming": "android/support/design/animation/MotionTiming",
+ "android/support/design/animation/ImageMatrixProperty": "android/support/design/animation/ImageMatrixProperty",
+ "android/support/design/animation/MatrixEvaluator": "android/support/design/animation/MatrixEvaluator",
+ "android/support/design/animation/AnimatorSetCompat": "android/support/design/animation/AnimatorSetCompat",
+ "android/support/design/widget/ViewOffsetBehavior": "android/support/design/widget/ViewOffsetBehavior",
+ "android/support/design/widget/HideBottomViewOnScrollBehavior": "android/support/design/widget/HideBottomViewOnScrollBehavior",
+ "android/support/design/widget/IndicatorViewController": "android/support/design/widget/IndicatorViewController",
+ "android/support/design/widget/TextInputLayout": "android/support/design/widget/TextInputLayout",
+ "android/support/v4/widget/Space": "androidx/legacy/widget/Space",
+ "android/support/v7/widget/AppCompatTextView": "androidx/appcompat/widget/AppCompatTextView",
+ "android/support/design/widget/NavigationView": "android/support/design/widget/NavigationView",
+ "android/support/v7/graphics/drawable/DrawableWrapper": "androidx/appcompat/graphics/drawable/DrawableWrapper",
+ "android/support/design/widget/Snackbar": "android/support/design/widget/Snackbar",
+ "android/support/annotation/StringRes": "androidx/annotation/StringRes",
+ "android/support/design/widget/TabItem": "android/support/design/widget/TabItem",
+ "android/support/design/widget/TabLayout": "android/support/design/widget/TabLayout",
+ "android/support/v4/view/ViewPager": "androidx/viewpager/widget/ViewPager",
+ "android/support/v4/view/PagerAdapter": "androidx/viewpager/widget/PagerAdapter",
+ "android/support/v7/app/ActionBar": "androidx/appcompat/app/ActionBar",
+ "android/support/v4/view/MarginLayoutParamsCompat": "androidx/core/view/MarginLayoutParamsCompat",
+ "android/support/annotation/ColorRes": "androidx/annotation/ColorRes",
+ "android/support/design/widget/TextInputEditText": "android/support/design/widget/TextInputEditText",
+ "android/support/v7/widget/AppCompatEditText": "androidx/appcompat/widget/AppCompatEditText",
+ "android/support/v7/widget/DrawableUtils": "androidx/appcompat/widget/DrawableUtils",
"android/support/v17/leanback/animation/LogAccelerateInterpolator": "androidx/leanback/animation/LogAccelerateInterpolator",
"android/support/v17/leanback/animation/LogDecelerateInterpolator": "androidx/leanback/animation/LogDecelerateInterpolator",
"android/support/v17/leanback/app/BackgroundFragment": "androidx/leanback/app/BackgroundFragment",
@@ -2922,7 +2663,6 @@
"android/support/v17/leanback/app/BaseRowFragment": "androidx/leanback/app/BaseRowFragment",
"android/support/v17/leanback/widget/OnChildViewHolderSelectedListener": "androidx/leanback/widget/OnChildViewHolderSelectedListener",
"android/support/v17/leanback/widget/ItemBridgeAdapter": "androidx/leanback/widget/ItemBridgeAdapter",
- "android/support/v17/leanback/widget/VerticalGridView": "androidx/leanback/widget/VerticalGridView",
"android/support/v17/leanback/widget/ObjectAdapter": "androidx/leanback/widget/ObjectAdapter",
"android/support/v17/leanback/widget/PresenterSelector": "androidx/leanback/widget/PresenterSelector",
"android/support/v17/leanback/widget/Row": "androidx/leanback/widget/Row",
@@ -2948,6 +2688,7 @@
"android/support/v17/leanback/widget/InvisibleRowPresenter": "androidx/leanback/widget/InvisibleRowPresenter",
"android/support/v17/leanback/app/BrowseSupportFragment": "androidx/leanback/app/BrowseSupportFragment",
"android/support/v17/leanback/app/HeadersSupportFragment": "androidx/leanback/app/HeadersSupportFragment",
+ "android/support/v4/app/FragmentTransaction": "androidx/fragment/app/FragmentTransaction",
"android/support/v17/leanback/app/RowsSupportFragment": "androidx/leanback/app/RowsSupportFragment",
"android/support/v17/leanback/app/DetailsBackgroundVideoHelper": "androidx/leanback/app/DetailsBackgroundVideoHelper",
"android/support/v17/leanback/widget/ParallaxTarget": "androidx/leanback/widget/ParallaxTarget",
@@ -2981,6 +2722,7 @@
"android/support/v17/leanback/widget/DiffCallback": "androidx/leanback/widget/DiffCallback",
"android/support/v17/leanback/app/GuidedStepRootLayout": "androidx/leanback/app/GuidedStepRootLayout",
"android/support/v17/leanback/widget/NonOverlappingLinearLayout": "androidx/leanback/widget/NonOverlappingLinearLayout",
+ "android/support/v4/app/ActivityCompat": "androidx/core/app/ActivityCompat",
"android/support/v17/leanback/widget/Util": "androidx/leanback/widget/Util",
"android/support/v17/leanback/app/GuidedStepSupportFragment": "androidx/leanback/app/GuidedStepSupportFragment",
"android/support/v17/leanback/widget/FocusHighlightHelper": "androidx/leanback/widget/FocusHighlightHelper",
@@ -3038,7 +2780,6 @@
"android/support/v17/leanback/widget/PlaybackTransportRowPresenter": "androidx/leanback/widget/PlaybackTransportRowPresenter",
"android/support/v17/leanback/system/Settings": "androidx/leanback/system/Settings",
"android/support/v17/leanback/widget/ShadowOverlayContainer": "androidx/leanback/widget/ShadowOverlayContainer",
- "android/support/v17/leanback/transition/FadeAndShortSlide": "androidx/leanback/transition/FadeAndShortSlide",
"android/support/v17/leanback/transition/TranslationAnimationCreator": "androidx/leanback/transition/TranslationAnimationCreator",
"android/support/v17/leanback/transition/LeanbackTransitionHelper": "androidx/leanback/transition/LeanbackTransitionHelper",
"android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat": "androidx/leanback/transition/LeanbackTransitionHelperKitKat",
@@ -3058,7 +2799,6 @@
"android/support/v17/leanback/widget/BaseCardView": "androidx/leanback/widget/BaseCardView",
"android/support/v17/leanback/widget/GridLayoutManager": "androidx/leanback/widget/GridLayoutManager",
"android/support/v17/leanback/widget/WindowAlignment": "androidx/leanback/widget/WindowAlignment",
- "android/support/v7/widget/SimpleItemAnimator": "androidx/recyclerview/widget/SimpleItemAnimator",
"android/support/v17/leanback/widget/OnChildSelectedListener": "androidx/leanback/widget/OnChildSelectedListener",
"android/support/v17/leanback/widget/ViewsStateBundle": "androidx/leanback/widget/ViewsStateBundle",
"android/support/v17/leanback/widget/BrowseRowsFrameLayout": "androidx/leanback/widget/BrowseRowsFrameLayout",
@@ -3072,6 +2812,7 @@
"android/support/v17/leanback/widget/DetailsOverviewRowPresenter": "androidx/leanback/widget/DetailsOverviewRowPresenter",
"android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper": "androidx/leanback/widget/DetailsOverviewSharedElementHelper",
"android/support/v17/leanback/widget/RoundedRectHelper": "androidx/leanback/widget/RoundedRectHelper",
+ "android/support/v4/app/SharedElementCallback": "androidx/core/app/SharedElementCallback",
"android/support/v17/leanback/widget/RecyclerViewParallax": "androidx/leanback/widget/RecyclerViewParallax",
"android/support/v17/leanback/widget/FacetProvider": "androidx/leanback/widget/FacetProvider",
"android/support/v17/leanback/widget/FacetProviderAdapter": "androidx/leanback/widget/FacetProviderAdapter",
@@ -3085,10 +2826,8 @@
"android/support/v4/util/CircularIntArray": "androidx/collection/CircularIntArray",
"android/support/v17/leanback/widget/SingleRow": "androidx/leanback/widget/SingleRow",
"android/support/v17/leanback/widget/StaggeredGridDefault": "androidx/leanback/widget/StaggeredGridDefault",
- "android/support/v7/widget/LinearSmoothScroller": "androidx/recyclerview/widget/LinearSmoothScroller",
"android/support/v17/leanback/widget/ItemAlignmentFacetHelper": "androidx/leanback/widget/ItemAlignmentFacetHelper",
"android/support/v17/leanback/widget/ItemAlignment": "androidx/leanback/widget/ItemAlignment",
- "android/support/v7/widget/OrientationHelper": "androidx/recyclerview/widget/OrientationHelper",
"android/support/v17/leanback/widget/GuidanceStylingRelativeLayout": "androidx/leanback/widget/GuidanceStylingRelativeLayout",
"android/support/v17/leanback/widget/ImeKeyMonitor": "androidx/leanback/widget/ImeKeyMonitor",
"android/support/v17/leanback/widget/GuidedActionDiffCallback": "androidx/leanback/widget/GuidedActionDiffCallback",
@@ -3131,131 +2870,29 @@
"android/support/v4/util/CircularArray": "androidx/collection/CircularArray",
"android/support/v17/leanback/widget/TitleView": "androidx/leanback/widget/TitleView",
"android/support/v17/leanback/widget/VideoSurfaceView": "androidx/leanback/widget/VideoSurfaceView",
+ "android/support/v4/util/LruCache": "androidx/collection/LruCache",
"android/support/v17/leanback/widget/Visibility": "androidx/leanback/widget/Visibility",
"android/support/v17/leanback/widget/picker/Picker": "androidx/leanback/widget/picker/Picker",
"android/support/v17/leanback/widget/picker/PickerUtility": "androidx/leanback/widget/picker/PickerUtility",
"android/support/v17/leanback/widget/picker/PickerColumn": "androidx/leanback/widget/picker/PickerColumn",
"android/support/v17/leanback/widget/picker/TimePicker": "androidx/leanback/widget/picker/TimePicker",
- "android/support/v4/provider/DocumentFile": "androidx/documentfile/provider/DocumentFile",
- "android/support/v4/provider/RawDocumentFile": "androidx/documentfile/provider/RawDocumentFile",
- "android/support/v4/provider/SingleDocumentFile": "androidx/documentfile/provider/SingleDocumentFile",
- "android/support/v4/provider/TreeDocumentFile": "androidx/documentfile/provider/TreeDocumentFile",
- "android/support/v4/provider/DocumentsContractApi19": "androidx/documentfile/provider/DocumentsContractApi19",
- "android/arch/lifecycle/EmptyActivityLifecycleCallbacks": "androidx/lifecycle/EmptyActivityLifecycleCallbacks",
- "android/arch/lifecycle/HolderFragment": "androidx/lifecycle/HolderFragment",
- "android/arch/lifecycle/LifecycleDispatcher": "androidx/lifecycle/LifecycleDispatcher",
- "android/arch/lifecycle/LifecycleService": "androidx/lifecycle/LifecycleService",
- "android/arch/lifecycle/ServiceLifecycleDispatcher": "androidx/lifecycle/ServiceLifecycleDispatcher",
- "android/arch/lifecycle/ProcessLifecycleOwner": "androidx/lifecycle/ProcessLifecycleOwner",
- "android/arch/lifecycle/ProcessLifecycleOwnerInitializer": "androidx/lifecycle/ProcessLifecycleOwnerInitializer",
- "android/arch/lifecycle/ViewModelProviders": "androidx/lifecycle/ViewModelProviders",
- "android/arch/lifecycle/ViewModelStores": "androidx/lifecycle/ViewModelStores",
- "android/arch/persistence/room/testing/MigrationTestHelper": "androidx/room/testing/MigrationTestHelper",
- "android/support/wear/ambient/AmbientDelegate": "androidx/wear/ambient/AmbientDelegate",
- "android/support/wear/ambient/WearableControllerProvider": "androidx/wear/ambient/WearableControllerProvider",
- "android/support/wear/ambient/AmbientMode": "androidx/wear/ambient/AmbientMode",
- "android/support/wear/ambient/AmbientModeSupport": "androidx/wear/ambient/AmbientModeSupport",
- "android/support/wear/ambient/SharedLibraryVersion": "androidx/wear/ambient/SharedLibraryVersion",
- "android/support/wear/internal/widget/ResourcesUtil": "androidx/wear/internal/widget/ResourcesUtil",
- "android/support/wear/internal/widget/drawer/MultiPagePresenter": "androidx/wear/internal/widget/drawer/MultiPagePresenter",
- "android/support/wear/widget/drawer/WearableNavigationDrawerView": "androidx/wear/widget/drawer/WearableNavigationDrawerView",
- "android/support/wear/internal/widget/drawer/WearableNavigationDrawerPresenter": "androidx/wear/internal/widget/drawer/WearableNavigationDrawerPresenter",
- "android/support/wear/widget/drawer/WearableDrawerController": "androidx/wear/widget/drawer/WearableDrawerController",
- "android/support/wear/internal/widget/drawer/MultiPageUi": "androidx/wear/internal/widget/drawer/MultiPageUi",
- "android/support/wear/R": "androidx/wear/R",
- "android/support/wear/widget/drawer/PageIndicatorView": "androidx/wear/widget/drawer/PageIndicatorView",
- "android/support/wear/internal/widget/drawer/SinglePagePresenter": "androidx/wear/internal/widget/drawer/SinglePagePresenter",
- "android/support/wear/internal/widget/drawer/SinglePageUi": "androidx/wear/internal/widget/drawer/SinglePageUi",
- "android/support/wear/widget/CircledImageView": "androidx/wear/widget/CircledImageView",
- "android/support/wear/utils/MetadataConstants": "androidx/wear/utils/MetadataConstants",
- "android/support/wear/widget/BezierSCurveInterpolator": "androidx/wear/widget/BezierSCurveInterpolator",
- "android/support/wear/widget/BoxInsetLayout": "androidx/wear/widget/BoxInsetLayout",
- "android/support/wear/widget/ProgressDrawable": "androidx/wear/widget/ProgressDrawable",
- "android/support/wear/widget/CircularProgressLayout": "androidx/wear/widget/CircularProgressLayout",
- "android/support/wear/widget/CircularProgressLayoutController": "androidx/wear/widget/CircularProgressLayoutController",
- "android/support/wear/widget/CurvingLayoutCallback": "androidx/wear/widget/CurvingLayoutCallback",
- "android/support/wear/widget/WearableLinearLayoutManager": "androidx/wear/widget/WearableLinearLayoutManager",
- "android/support/wear/widget/RoundedDrawable": "androidx/wear/widget/RoundedDrawable",
- "android/support/wear/widget/ScrollManager": "androidx/wear/widget/ScrollManager",
- "android/support/wear/widget/SimpleAnimatorListener": "androidx/wear/widget/SimpleAnimatorListener",
- "android/support/wear/widget/SwipeDismissFrameLayout": "androidx/wear/widget/SwipeDismissFrameLayout",
- "android/support/wear/widget/SwipeDismissLayout": "androidx/wear/widget/SwipeDismissLayout",
- "android/support/wear/widget/WearableRecyclerView": "androidx/wear/widget/WearableRecyclerView",
- "android/support/wear/widget/drawer/AbsListViewFlingWatcher": "androidx/wear/widget/drawer/AbsListViewFlingWatcher",
- "android/support/wear/widget/drawer/FlingWatcherFactory": "androidx/wear/widget/drawer/FlingWatcherFactory",
- "android/support/wear/widget/drawer/RecyclerViewFlingWatcher": "androidx/wear/widget/drawer/RecyclerViewFlingWatcher",
- "android/support/wear/widget/drawer/ScrollViewFlingWatcher": "androidx/wear/widget/drawer/ScrollViewFlingWatcher",
- "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher",
- "android/support/wear/widget/drawer/WearableActionDrawerMenu": "androidx/wear/widget/drawer/WearableActionDrawerMenu",
- "android/support/wear/widget/drawer/WearableActionDrawerView": "androidx/wear/widget/drawer/WearableActionDrawerView",
- "android/support/wear/widget/drawer/WearableDrawerView": "androidx/wear/widget/drawer/WearableDrawerView",
- "android/support/wear/widget/drawer/WearableDrawerLayout": "androidx/wear/widget/drawer/WearableDrawerLayout",
- "android/support/v4/content/LocalBroadcastManager": "androidx/localbroadcastmanager/content/LocalBroadcastManager",
- "android/support/v4/print/PrintHelper": "androidx/print/PrintHelper",
- "android/support/media/ExifInterface": "androidx/exifinterface/media/ExifInterface",
- "android/support/v7/app/MediaRouteActionProvider": "androidx/mediarouter/app/MediaRouteActionProvider",
- "android/support/v7/media/MediaRouter": "androidx/mediarouter/media/MediaRouter",
- "android/support/v7/media/MediaRouteSelector": "androidx/mediarouter/media/MediaRouteSelector",
- "android/support/v7/app/MediaRouteDialogFactory": "androidx/mediarouter/app/MediaRouteDialogFactory",
- "android/support/v7/app/MediaRouteButton": "androidx/mediarouter/app/MediaRouteButton",
- "android/support/v7/mediarouter/R": "androidx/mediarouter/R",
- "android/support/v7/app/MediaRouterThemeHelper": "androidx/mediarouter/app/MediaRouterThemeHelper",
- "android/support/v7/app/MediaRouteChooserDialogFragment": "androidx/mediarouter/app/MediaRouteChooserDialogFragment",
- "android/support/v7/app/MediaRouteControllerDialogFragment": "androidx/mediarouter/app/MediaRouteControllerDialogFragment",
- "android/support/v7/app/MediaRouteChooserDialog": "androidx/mediarouter/app/MediaRouteChooserDialog",
- "android/support/v7/app/MediaRouteDialogHelper": "androidx/mediarouter/app/MediaRouteDialogHelper",
- "android/support/v7/app/MediaRouteControllerDialog": "androidx/mediarouter/app/MediaRouteControllerDialog",
- "android/support/v7/app/OverlayListView": "androidx/mediarouter/app/OverlayListView",
- "android/support/v7/app/MediaRouteVolumeSlider": "androidx/mediarouter/app/MediaRouteVolumeSlider",
- "android/support/v7/app/AlertDialog": "androidx/appcompat/app/AlertDialog",
- "android/support/v7/app/MediaRouteExpandCollapseButton": "androidx/mediarouter/app/MediaRouteExpandCollapseButton",
- "android/support/v7/app/MediaRouteDiscoveryFragment": "androidx/mediarouter/app/MediaRouteDiscoveryFragment",
- "android/support/v7/widget/AppCompatSeekBar": "androidx/appcompat/widget/AppCompatSeekBar",
- "android/support/v7/media/MediaControlIntent": "androidx/mediarouter/media/MediaControlIntent",
- "android/support/v7/media/MediaItemMetadata": "androidx/mediarouter/media/MediaItemMetadata",
- "android/support/v7/media/MediaItemStatus": "androidx/mediarouter/media/MediaItemStatus",
- "android/support/v7/media/MediaRouteDescriptor": "androidx/mediarouter/media/MediaRouteDescriptor",
- "android/support/v7/media/MediaRouteDiscoveryRequest": "androidx/mediarouter/media/MediaRouteDiscoveryRequest",
- "android/support/v7/media/MediaRouteProvider": "androidx/mediarouter/media/MediaRouteProvider",
- "android/support/v7/media/MediaRouteProviderDescriptor": "androidx/mediarouter/media/MediaRouteProviderDescriptor",
- "android/support/v7/media/MediaRouteProviderProtocol": "androidx/mediarouter/media/MediaRouteProviderProtocol",
- "android/support/v7/media/MediaRouteProviderService": "androidx/mediarouter/media/MediaRouteProviderService",
- "android/support/v7/media/SystemMediaRouteProvider": "androidx/mediarouter/media/SystemMediaRouteProvider",
- "android/support/v7/media/RemoteControlClientCompat": "androidx/mediarouter/media/RemoteControlClientCompat",
- "android/support/v7/media/RegisteredMediaRouteProviderWatcher": "androidx/mediarouter/media/RegisteredMediaRouteProviderWatcher",
- "android/support/v7/media/MediaRouterApi24": "androidx/mediarouter/media/MediaRouterApi24",
- "android/support/v7/media/MediaRouterJellybean": "androidx/mediarouter/media/MediaRouterJellybean",
- "android/support/v7/media/MediaRouterJellybeanMr1": "androidx/mediarouter/media/MediaRouterJellybeanMr1",
- "android/support/v7/media/MediaRouterJellybeanMr2": "androidx/mediarouter/media/MediaRouterJellybeanMr2",
- "android/support/v7/media/MediaSessionStatus": "androidx/mediarouter/media/MediaSessionStatus",
- "android/support/v7/media/RegisteredMediaRouteProvider": "androidx/mediarouter/media/RegisteredMediaRouteProvider",
- "android/support/v7/media/RemotePlaybackClient": "androidx/mediarouter/media/RemotePlaybackClient",
- "android/support/graphics/drawable/Animatable2Compat": "androidx/vectordrawable/graphics/drawable/Animatable2Compat",
- "android/support/graphics/drawable/AnimatedVectorDrawableCompat": "androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat",
- "android/support/graphics/drawable/VectorDrawableCompat": "androidx/vectordrawable/graphics/drawable/VectorDrawableCompat",
- "android/support/graphics/drawable/VectorDrawableCommon": "androidx/vectordrawable/graphics/drawable/VectorDrawableCommon",
- "android/support/graphics/drawable/AndroidResources": "androidx/vectordrawable/graphics/drawable/AndroidResources",
- "android/support/graphics/drawable/AnimatorInflaterCompat": "androidx/vectordrawable/graphics/drawable/AnimatorInflaterCompat",
- "android/support/graphics/drawable/AnimationUtilsCompat": "androidx/vectordrawable/graphics/drawable/AnimationUtilsCompat",
- "android/support/graphics/drawable/PathInterpolatorCompat": "androidx/vectordrawable/graphics/drawable/PathInterpolatorCompat",
- "android/support/graphics/drawable/ArgbEvaluator": "androidx/vectordrawable/graphics/drawable/ArgbEvaluator",
- "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout": "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout",
- "android/support/v17/preference/BaseLeanbackPreferenceFragment": "androidx/leanback/preference/BaseLeanbackPreferenceFragment",
- "android/support/v14/preference/PreferenceFragment": "androidx/preference/PreferenceFragment",
- "android/support/v17/preference/R": "androidx/leanback/preference/R",
- "android/support/v7/preference/PreferenceRecyclerViewAccessibilityDelegate": "androidx/preference/PreferenceRecyclerViewAccessibilityDelegate",
- "android/support/v7/widget/RecyclerViewAccessibilityDelegate": "androidx/recyclerview/widget/RecyclerViewAccessibilityDelegate",
- "android/support/v17/preference/LeanbackListPreferenceDialogFragment": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment",
- "android/support/v7/preference/DialogPreference": "androidx/preference/DialogPreference",
- "android/support/v14/preference/MultiSelectListPreference": "androidx/preference/MultiSelectListPreference",
- "android/support/v7/preference/ListPreference": "androidx/preference/ListPreference",
- "android/support/v17/preference/LeanbackPreferenceDialogFragment": "androidx/leanback/preference/LeanbackPreferenceDialogFragment",
- "android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21": "androidx/leanback/preference/LeanbackPreferenceFragmentTransitionHelperApi21",
- "android/support/v7/preference/Preference": "androidx/preference/Preference",
- "android/support/v17/preference/LeanbackPreferenceFragment": "androidx/leanback/preference/LeanbackPreferenceFragment",
- "android/support/v7/preference/PreferenceScreen": "androidx/preference/PreferenceScreen",
- "android/support/v17/preference/LeanbackSettingsFragment": "androidx/leanback/preference/LeanbackSettingsFragment",
- "android/support/v17/preference/LeanbackSettingsRootView": "androidx/leanback/preference/LeanbackSettingsRootView",
+ "android/support/app/recommendation/ContentRecommendation": "androidx/recommendation/app/ContentRecommendation",
+ "android/support/app/recommendation/RecommendationExtender": "androidx/recommendation/app/RecommendationExtender",
+ "android/support/annotation/FloatRange": "androidx/annotation/FloatRange",
+ "android/support/v4/os/LocaleListCompat": "androidx/core/os/LocaleListCompat",
+ "android/support/design/animation/ArgbEvaluatorCompat": "android/support/design/animation/ArgbEvaluatorCompat",
+ "android/support/design/animation/ChildrenAlphaProperty": "android/support/design/animation/ChildrenAlphaProperty",
+ "android/support/design/animation/R": "android/support/design/animation/R",
+ "android/support/design/animation/DrawableAlphaProperty": "android/support/design/animation/DrawableAlphaProperty",
+ "android/support/design/animation/Positioning": "android/support/design/animation/Positioning",
+ "android/support/design/circularreveal/CircularRevealCompat": "android/support/design/circularreveal/CircularRevealCompat",
+ "android/support/design/circularreveal/CircularRevealWidget": "android/support/design/circularreveal/CircularRevealWidget",
+ "android/support/design/circularreveal/CircularRevealFrameLayout": "android/support/design/circularreveal/CircularRevealFrameLayout",
+ "android/support/design/circularreveal/CircularRevealHelper": "android/support/design/circularreveal/CircularRevealHelper",
+ "android/support/design/circularreveal/CircularRevealGridLayout": "android/support/design/circularreveal/CircularRevealGridLayout",
+ "android/support/design/math/MathUtils": "android/support/design/math/MathUtils",
+ "android/support/design/circularreveal/CircularRevealLinearLayout": "android/support/design/circularreveal/CircularRevealLinearLayout",
+ "android/support/design/circularreveal/CircularRevealRelativeLayout": "android/support/design/circularreveal/CircularRevealRelativeLayout",
"android/support/transition/AnimatorUtils": "androidx/transition/AnimatorUtils",
"android/support/transition/AnimatorUtilsImpl": "androidx/transition/AnimatorUtilsImpl",
"android/support/transition/AnimatorUtilsApi19": "androidx/transition/AnimatorUtilsApi19",
@@ -3263,12 +2900,8 @@
"android/support/transition/ArcMotion": "androidx/transition/ArcMotion",
"android/support/transition/PathMotion": "androidx/transition/PathMotion",
"android/support/transition/Styleable": "androidx/transition/Styleable",
- "android/support/transition/AutoTransition": "androidx/transition/AutoTransition",
- "android/support/transition/TransitionSet": "androidx/transition/TransitionSet",
"android/support/transition/Fade": "androidx/transition/Fade",
- "android/support/transition/Transition": "androidx/transition/Transition",
"android/support/transition/ChangeBounds": "androidx/transition/ChangeBounds",
- "android/support/transition/TransitionValues": "androidx/transition/TransitionValues",
"android/support/transition/ViewUtils": "androidx/transition/ViewUtils",
"android/support/transition/ViewOverlayImpl": "androidx/transition/ViewOverlayImpl",
"android/support/transition/TransitionListenerAdapter": "androidx/transition/TransitionListenerAdapter",
@@ -3294,7 +2927,7 @@
"android/support/transition/TransitionPropagation": "androidx/transition/TransitionPropagation",
"android/support/transition/TranslationAnimationCreator": "androidx/transition/TranslationAnimationCreator",
"android/support/transition/FragmentTransitionSupport": "androidx/transition/FragmentTransitionSupport",
- "android/support/transition/TransitionManager": "androidx/transition/TransitionManager",
+ "android/support/v4/app/FragmentTransitionImpl": "androidx/fragment/app/FragmentTransitionImpl",
"android/support/transition/GhostViewApi14": "androidx/transition/GhostViewApi14",
"android/support/transition/GhostViewApi21": "androidx/transition/GhostViewApi21",
"android/support/transition/ImageViewUtilsImpl": "androidx/transition/ImageViewUtilsImpl",
@@ -3330,75 +2963,138 @@
"android/support/transition/ViewUtilsApi14": "androidx/transition/ViewUtilsApi14",
"android/support/transition/WindowIdApi14": "androidx/transition/WindowIdApi14",
"android/support/transition/WindowIdApi18": "androidx/transition/WindowIdApi18",
- "android/support/v14/preference/EditTextPreferenceDialogFragment": "androidx/preference/EditTextPreferenceDialogFragment",
- "android/support/v14/preference/PreferenceDialogFragment": "androidx/preference/PreferenceDialogFragment",
- "android/support/v7/preference/EditTextPreference": "androidx/preference/EditTextPreference",
- "android/support/v14/preference/ListPreferenceDialogFragment": "androidx/preference/ListPreferenceDialogFragment",
- "android/support/v7/preference/internal/AbstractMultiSelectListPreference": "androidx/preference/internal/AbstractMultiSelectListPreference",
- "android/support/v7/preference/R": "androidx/preference/R",
- "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": "androidx/preference/MultiSelectListPreferenceDialogFragment",
- "android/support/v7/preference/PreferenceGroup": "androidx/preference/PreferenceGroup",
- "android/support/v7/preference/PreferenceViewHolder": "androidx/preference/PreferenceViewHolder",
- "android/support/v7/preference/PreferenceManager": "androidx/preference/PreferenceManager",
- "android/support/v7/preference/PreferenceGroupAdapter": "androidx/preference/PreferenceGroupAdapter",
- "android/support/v14/preference/SwitchPreference": "androidx/preference/SwitchPreference",
- "android/support/v7/preference/TwoStatePreference": "androidx/preference/TwoStatePreference",
- "android/support/v7/internal/widget/PreferenceImageView": "androidx/preference/internal/PreferenceImageView",
- "android/support/v7/preference/AndroidResources": "androidx/preference/AndroidResources",
- "android/support/v7/preference/CheckBoxPreference": "androidx/preference/CheckBoxPreference",
- "android/support/v7/preference/CollapsiblePreferenceGroupController": "androidx/preference/CollapsiblePreferenceGroupController",
- "android/support/v7/preference/DropDownPreference": "androidx/preference/DropDownPreference",
- "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": "androidx/preference/EditTextPreferenceDialogFragmentCompat",
- "android/support/v7/preference/PreferenceDialogFragmentCompat": "androidx/preference/PreferenceDialogFragmentCompat",
- "android/support/v7/preference/ListPreferenceDialogFragmentCompat": "androidx/preference/ListPreferenceDialogFragmentCompat",
- "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat",
- "android/support/v7/preference/PreferenceDataStore": "androidx/preference/PreferenceDataStore",
- "android/support/v7/preference/PreferenceCategory": "androidx/preference/PreferenceCategory",
- "android/support/v7/preference/PreferenceFragmentCompat": "androidx/preference/PreferenceFragmentCompat",
- "android/support/v7/preference/PreferenceInflater": "androidx/preference/PreferenceInflater",
- "android/support/v7/preference/SeekBarPreference": "androidx/preference/SeekBarPreference",
- "android/support/v7/preference/SwitchPreferenceCompat": "androidx/preference/SwitchPreferenceCompat",
- "android/support/v7/preference/UnPressableLinearLayout": "androidx/preference/UnPressableLinearLayout",
- "android/support/v7/view/menu/SubMenuBuilder": "androidx/appcompat/view/menu/SubMenuBuilder",
- "android/support/v7/widget/LinearLayoutCompat": "androidx/appcompat/widget/LinearLayoutCompat",
- "android/support/v4/view/PagerTabStrip": "androidx/viewpager/widget/PagerTabStrip",
- "android/support/v4/view/PagerTitleStrip": "androidx/viewpager/widget/PagerTitleStrip",
- "android/support/v7/recyclerview/extensions/AsyncListDiffer": "androidx/recyclerview/widget/AsyncListDiffer",
- "android/support/v7/recyclerview/extensions/ListAdapter": "androidx/recyclerview/widget/ListAdapter",
- "android/support/v7/util/AsyncListUtil": "androidx/recyclerview/widget/AsyncListUtil",
- "android/support/v7/util/ThreadUtil": "androidx/recyclerview/widget/ThreadUtil",
- "android/support/v7/util/TileList": "androidx/recyclerview/widget/TileList",
- "android/support/v7/util/MessageThreadUtil": "androidx/recyclerview/widget/MessageThreadUtil",
- "android/support/v7/util/BatchingListUpdateCallback": "androidx/recyclerview/widget/BatchingListUpdateCallback",
- "android/support/v7/util/SortedList": "androidx/recyclerview/widget/SortedList",
- "android/support/v7/widget/AdapterHelper": "androidx/recyclerview/widget/AdapterHelper",
- "android/support/v7/widget/OpReorderer": "androidx/recyclerview/widget/OpReorderer",
- "android/support/v7/widget/ChildHelper": "androidx/recyclerview/widget/ChildHelper",
- "android/support/v7/widget/DefaultItemAnimator": "androidx/recyclerview/widget/DefaultItemAnimator",
- "android/support/v7/widget/DividerItemDecoration": "androidx/recyclerview/widget/DividerItemDecoration",
- "android/support/v7/widget/FastScroller": "androidx/recyclerview/widget/FastScroller",
- "android/support/v7/widget/GapWorker": "androidx/recyclerview/widget/GapWorker",
- "android/support/v7/widget/GridLayoutManager": "androidx/recyclerview/widget/GridLayoutManager",
- "android/support/v7/widget/LayoutState": "androidx/recyclerview/widget/LayoutState",
- "android/support/v7/widget/helper/ItemTouchHelper": "androidx/recyclerview/widget/ItemTouchHelper",
- "android/support/v7/widget/ScrollbarHelper": "androidx/recyclerview/widget/ScrollbarHelper",
- "android/support/v7/widget/ViewBoundsCheck": "androidx/recyclerview/widget/ViewBoundsCheck",
- "android/support/v7/widget/LinearSnapHelper": "androidx/recyclerview/widget/LinearSnapHelper",
- "android/support/v7/widget/SnapHelper": "androidx/recyclerview/widget/SnapHelper",
- "android/support/v7/widget/PagerSnapHelper": "androidx/recyclerview/widget/PagerSnapHelper",
- "android/support/v7/widget/PositionMap": "androidx/recyclerview/widget/PositionMap",
- "android/support/v7/widget/ViewInfoStore": "androidx/recyclerview/widget/ViewInfoStore",
- "android/support/v7/recyclerview/R": "androidx/recyclerview/R",
- "android/support/v7/widget/StaggeredGridLayoutManager": "androidx/recyclerview/widget/StaggeredGridLayoutManager",
- "android/support/v7/widget/helper/ItemTouchUIUtilImpl": "androidx/recyclerview/widget/ItemTouchUIUtilImpl",
- "android/support/v7/widget/helper/ItemTouchUIUtil": "androidx/recyclerview/widget/ItemTouchUIUtil",
- "android/support/v7/widget/util/SortedListAdapterCallback": "androidx/recyclerview/widget/SortedListAdapterCallback",
- "android/support/v4/util/MapCollections": "androidx/collection/MapCollections",
- "android/support/v4/util/ContainerHelpers": "androidx/collection/ContainerHelpers",
- "android/support/content/ContentPager": "androidx/contentpager/content/ContentPager",
- "android/support/content/Query": "androidx/contentpager/content/Query",
- "android/support/content/InMemoryCursor": "androidx/contentpager/content/InMemoryCursor",
- "android/support/content/LoaderQueryRunner": "androidx/contentpager/content/LoaderQueryRunner",
+ "android/support/wear/ambient/AmbientDelegate": "androidx/wear/ambient/AmbientDelegate",
+ "android/support/wear/ambient/WearableControllerProvider": "androidx/wear/ambient/WearableControllerProvider",
+ "android/support/wear/ambient/AmbientMode": "androidx/wear/ambient/AmbientMode",
+ "android/support/wear/ambient/AmbientModeSupport": "androidx/wear/ambient/AmbientModeSupport",
+ "android/support/wear/ambient/SharedLibraryVersion": "androidx/wear/ambient/SharedLibraryVersion",
+ "android/support/wear/internal/widget/ResourcesUtil": "androidx/wear/internal/widget/ResourcesUtil",
+ "android/support/annotation/FractionRes": "androidx/annotation/FractionRes",
+ "android/support/wear/internal/widget/drawer/MultiPagePresenter": "androidx/wear/internal/widget/drawer/MultiPagePresenter",
+ "android/support/wear/widget/drawer/WearableNavigationDrawerView": "androidx/wear/widget/drawer/WearableNavigationDrawerView",
+ "android/support/wear/internal/widget/drawer/WearableNavigationDrawerPresenter": "androidx/wear/internal/widget/drawer/WearableNavigationDrawerPresenter",
+ "android/support/wear/widget/drawer/WearableDrawerController": "androidx/wear/widget/drawer/WearableDrawerController",
+ "android/support/wear/internal/widget/drawer/MultiPageUi": "androidx/wear/internal/widget/drawer/MultiPageUi",
+ "android/support/wear/R": "androidx/wear/R",
+ "android/support/wear/widget/drawer/PageIndicatorView": "androidx/wear/widget/drawer/PageIndicatorView",
+ "android/support/wear/internal/widget/drawer/SinglePagePresenter": "androidx/wear/internal/widget/drawer/SinglePagePresenter",
+ "android/support/wear/internal/widget/drawer/SinglePageUi": "androidx/wear/internal/widget/drawer/SinglePageUi",
+ "android/support/wear/widget/CircledImageView": "androidx/wear/widget/CircledImageView",
+ "android/support/wear/utils/MetadataConstants": "androidx/wear/utils/MetadataConstants",
+ "android/support/wear/widget/BezierSCurveInterpolator": "androidx/wear/widget/BezierSCurveInterpolator",
+ "android/support/wear/widget/BoxInsetLayout": "androidx/wear/widget/BoxInsetLayout",
+ "android/support/wear/widget/ProgressDrawable": "androidx/wear/widget/ProgressDrawable",
+ "android/support/wear/widget/CircularProgressLayout": "androidx/wear/widget/CircularProgressLayout",
+ "android/support/v4/widget/CircularProgressDrawable": "androidx/swiperefreshlayout/widget/CircularProgressDrawable",
+ "android/support/wear/widget/CircularProgressLayoutController": "androidx/wear/widget/CircularProgressLayoutController",
+ "android/support/wear/widget/CurvingLayoutCallback": "androidx/wear/widget/CurvingLayoutCallback",
+ "android/support/wear/widget/WearableLinearLayoutManager": "androidx/wear/widget/WearableLinearLayoutManager",
+ "android/support/wear/widget/RoundedDrawable": "androidx/wear/widget/RoundedDrawable",
+ "android/support/wear/widget/ScrollManager": "androidx/wear/widget/ScrollManager",
+ "android/support/wear/widget/SimpleAnimatorListener": "androidx/wear/widget/SimpleAnimatorListener",
+ "android/support/wear/widget/SwipeDismissFrameLayout": "androidx/wear/widget/SwipeDismissFrameLayout",
+ "android/support/wear/widget/SwipeDismissLayout": "androidx/wear/widget/SwipeDismissLayout",
+ "android/support/wear/widget/WearableRecyclerView": "androidx/wear/widget/WearableRecyclerView",
+ "android/support/wear/widget/drawer/AbsListViewFlingWatcher": "androidx/wear/widget/drawer/AbsListViewFlingWatcher",
+ "android/support/wear/widget/drawer/FlingWatcherFactory": "androidx/wear/widget/drawer/FlingWatcherFactory",
+ "android/support/wear/widget/drawer/RecyclerViewFlingWatcher": "androidx/wear/widget/drawer/RecyclerViewFlingWatcher",
+ "android/support/wear/widget/drawer/ScrollViewFlingWatcher": "androidx/wear/widget/drawer/ScrollViewFlingWatcher",
+ "android/support/v4/widget/NestedScrollView": "androidx/core/widget/NestedScrollView",
+ "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher",
+ "android/support/wear/widget/drawer/WearableActionDrawerMenu": "androidx/wear/widget/drawer/WearableActionDrawerMenu",
+ "android/support/wear/widget/drawer/WearableActionDrawerView": "androidx/wear/widget/drawer/WearableActionDrawerView",
+ "android/support/wear/widget/drawer/WearableDrawerView": "androidx/wear/widget/drawer/WearableDrawerView",
+ "android/support/wear/widget/drawer/WearableDrawerLayout": "androidx/wear/widget/drawer/WearableDrawerLayout",
+ "android/support/v4/view/NestedScrollingParent": "androidx/core/view/NestedScrollingParent",
+ "android/support/v4/view/NestedScrollingParentHelper": "androidx/core/view/NestedScrollingParentHelper",
+ "android/arch/lifecycle/ComputableLiveData": "androidx/lifecycle/ComputableLiveData",
+ "android/arch/core/executor/ArchTaskExecutor": "androidx/arch/core/executor/ArchTaskExecutor",
+ "android/arch/lifecycle/MediatorLiveData": "androidx/lifecycle/MediatorLiveData",
+ "android/arch/lifecycle/MutableLiveData": "androidx/lifecycle/MutableLiveData",
+ "android/arch/core/internal/SafeIterableMap": "androidx/arch/core/internal/SafeIterableMap",
+ "android/arch/lifecycle/Transformations": "androidx/lifecycle/Transformations",
+ "android/arch/core/util/Function": "androidx/arch/core/util/Function",
+ "android/arch/persistence/room/guava/GuavaRoom": "androidx/room/guava/GuavaRoom",
+ "android/arch/persistence/room/RoomSQLiteQuery": "androidx/room/RoomSQLiteQuery",
+ "android/support/v4/app/LoaderManager": "androidx/loader/app/LoaderManager",
+ "android/support/v4/content/Loader": "androidx/loader/content/Loader",
+ "android/arch/lifecycle/ViewModelStoreOwner": "androidx/lifecycle/ViewModelStoreOwner",
+ "android/support/v4/app/LoaderManagerImpl": "androidx/loader/app/LoaderManagerImpl",
+ "android/arch/lifecycle/ViewModelStore": "androidx/lifecycle/ViewModelStore",
+ "android/support/v4/util/DebugUtils": "androidx/core/util/DebugUtils",
+ "android/arch/lifecycle/ViewModelProvider": "androidx/lifecycle/ViewModelProvider",
+ "android/arch/lifecycle/ViewModel": "androidx/lifecycle/ViewModel",
+ "android/support/v4/content/AsyncTaskLoader": "androidx/loader/content/AsyncTaskLoader",
+ "android/support/v4/content/ModernAsyncTask": "androidx/loader/content/ModernAsyncTask",
+ "android/support/v4/os/OperationCanceledException": "androidx/core/os/OperationCanceledException",
+ "android/support/v4/content/CursorLoader": "androidx/loader/content/CursorLoader",
+ "android/support/v4/os/CancellationSignal": "androidx/core/os/CancellationSignal",
+ "android/support/v4/content/ContentResolverCompat": "androidx/core/content/ContentResolverCompat",
+ "android/support/v4/widget/DrawerLayout": "androidx/drawerlayout/widget/DrawerLayout",
+ "android/databinding/adapters/AbsListViewBindingAdapter": "androidx/databinding/adapters/AbsListViewBindingAdapter",
+ "android/databinding/adapters/AbsSeekBarBindingAdapter": "androidx/databinding/adapters/AbsSeekBarBindingAdapter",
+ "android/databinding/adapters/AbsSpinnerBindingAdapter": "androidx/databinding/adapters/AbsSpinnerBindingAdapter",
+ "android/databinding/adapters/ObservableListAdapter": "androidx/databinding/adapters/ObservableListAdapter",
+ "android/databinding/adapters/ActionMenuViewBindingAdapter": "androidx/databinding/adapters/ActionMenuViewBindingAdapter",
+ "android/databinding/adapters/AdapterViewBindingAdapter": "androidx/databinding/adapters/AdapterViewBindingAdapter",
+ "android/databinding/adapters/AutoCompleteTextViewBindingAdapter": "androidx/databinding/adapters/AutoCompleteTextViewBindingAdapter",
+ "android/databinding/adapters/CalendarViewBindingAdapter": "androidx/databinding/adapters/CalendarViewBindingAdapter",
+ "android/databinding/adapters/CardViewBindingAdapter": "androidx/databinding/adapters/CardViewBindingAdapter",
+ "android/databinding/adapters/CheckedTextViewBindingAdapter": "androidx/databinding/adapters/CheckedTextViewBindingAdapter",
+ "android/databinding/adapters/ChronometerBindingAdapter": "androidx/databinding/adapters/ChronometerBindingAdapter",
+ "android/databinding/adapters/CompoundButtonBindingAdapter": "androidx/databinding/adapters/CompoundButtonBindingAdapter",
+ "android/databinding/adapters/Converters": "androidx/databinding/adapters/Converters",
+ "android/databinding/adapters/DatePickerBindingAdapter": "androidx/databinding/adapters/DatePickerBindingAdapter",
+ "android/databinding/adapters/ListenerUtil": "androidx/databinding/adapters/ListenerUtil",
+ "android/databinding/adapters/ExpandableListViewBindingAdapter": "androidx/databinding/adapters/ExpandableListViewBindingAdapter",
+ "android/databinding/adapters/FrameLayoutBindingAdapter": "androidx/databinding/adapters/FrameLayoutBindingAdapter",
+ "android/databinding/adapters/ImageViewBindingAdapter": "androidx/databinding/adapters/ImageViewBindingAdapter",
+ "android/databinding/adapters/LinearLayoutBindingAdapter": "androidx/databinding/adapters/LinearLayoutBindingAdapter",
+ "android/databinding/adapters/NumberPickerBindingAdapter": "androidx/databinding/adapters/NumberPickerBindingAdapter",
+ "android/databinding/adapters/ProgressBarBindingAdapter": "androidx/databinding/adapters/ProgressBarBindingAdapter",
+ "android/databinding/adapters/RadioGroupBindingAdapter": "androidx/databinding/adapters/RadioGroupBindingAdapter",
+ "android/databinding/adapters/RatingBarBindingAdapter": "androidx/databinding/adapters/RatingBarBindingAdapter",
+ "android/databinding/adapters/SearchViewBindingAdapter": "androidx/databinding/adapters/SearchViewBindingAdapter",
+ "android/databinding/adapters/SeekBarBindingAdapter": "androidx/databinding/adapters/SeekBarBindingAdapter",
+ "android/databinding/adapters/SpinnerBindingAdapter": "androidx/databinding/adapters/SpinnerBindingAdapter",
+ "android/databinding/adapters/SwitchBindingAdapter": "androidx/databinding/adapters/SwitchBindingAdapter",
+ "android/databinding/adapters/SwitchCompatBindingAdapter": "androidx/databinding/adapters/SwitchCompatBindingAdapter",
+ "android/support/v7/widget/SwitchCompat": "androidx/appcompat/widget/SwitchCompat",
+ "android/databinding/adapters/TabHostBindingAdapter": "androidx/databinding/adapters/TabHostBindingAdapter",
+ "android/databinding/adapters/TabWidgetBindingAdapter": "androidx/databinding/adapters/TabWidgetBindingAdapter",
+ "android/databinding/adapters/TableLayoutBindingAdapter": "androidx/databinding/adapters/TableLayoutBindingAdapter",
+ "android/databinding/adapters/TextViewBindingAdapter": "androidx/databinding/adapters/TextViewBindingAdapter",
+ "android/databinding/adapters/TimePickerBindingAdapter": "androidx/databinding/adapters/TimePickerBindingAdapter",
+ "android/databinding/adapters/ToolbarBindingAdapter": "androidx/databinding/adapters/ToolbarBindingAdapter",
+ "android/databinding/adapters/VideoViewBindingAdapter": "androidx/databinding/adapters/VideoViewBindingAdapter",
+ "android/databinding/adapters/ViewBindingAdapter": "androidx/databinding/adapters/ViewBindingAdapter",
+ "android/databinding/adapters/ViewGroupBindingAdapter": "androidx/databinding/adapters/ViewGroupBindingAdapter",
+ "android/databinding/adapters/ViewStubBindingAdapter": "androidx/databinding/adapters/ViewStubBindingAdapter",
+ "android/databinding/adapters/ZoomControlsBindingAdapter": "androidx/databinding/adapters/ZoomControlsBindingAdapter",
+ "android/support/media/ExifInterface": "androidx/exifinterface/media/ExifInterface",
+ "android/arch/lifecycle/ErrorMessages": "androidx/lifecycle/ErrorMessages",
+ "android/arch/lifecycle/model/EventMethod": "androidx/lifecycle/model/EventMethod",
+ "android/arch/lifecycle/Elements_extKt": "androidx/lifecycle/Elements_extKt",
+ "android/arch/lifecycle/WriterKt": "androidx/lifecycle/WriterKt",
+ "android/arch/lifecycle/ObserversCollector": "androidx/lifecycle/ObserversCollector",
+ "android/arch/lifecycle/Validator": "androidx/lifecycle/Validator",
+ "android/arch/lifecycle/model/LifecycleObserverInfo": "androidx/lifecycle/model/LifecycleObserverInfo",
+ "android/arch/lifecycle/model/AdapterClassKt": "androidx/lifecycle/model/AdapterClassKt",
+ "android/arch/lifecycle/model/EventMethodCall": "androidx/lifecycle/model/EventMethodCall",
+ "android/arch/lifecycle/model/AdapterClass": "androidx/lifecycle/model/AdapterClass",
+ "android/arch/lifecycle/model/InputModel": "androidx/lifecycle/model/InputModel",
+ "android/arch/lifecycle/Lifecycling": "androidx/lifecycle/Lifecycling",
+ "android/arch/lifecycle/LifecycleProcessor": "androidx/lifecycle/LifecycleProcessor",
+ "android/arch/lifecycle/Input_collectorKt": "androidx/lifecycle/Input_collectorKt",
+ "android/arch/lifecycle/TransformationKt": "androidx/lifecycle/TransformationKt",
+ "android/arch/lifecycle/GeneratedAdapter": "androidx/lifecycle/GeneratedAdapter",
+ "android/arch/lifecycle/MethodCallsLogger": "androidx/lifecycle/MethodCallsLogger",
+ "android/support/design/bottomnavigation/LabelVisibilityMode": "android/support/design/bottomnavigation/LabelVisibilityMode",
+ "android/arch/lifecycle/LifecycleRegistry": "androidx/lifecycle/LifecycleRegistry",
+ "android/arch/lifecycle/GenericLifecycleObserver": "androidx/lifecycle/GenericLifecycleObserver",
+ "android/arch/core/internal/FastSafeIterableMap": "androidx/arch/core/internal/FastSafeIterableMap",
+ "android/arch/lifecycle/LifecycleRegistryOwner": "androidx/lifecycle/LifecycleRegistryOwner",
+ "android/arch/lifecycle/ReportFragment": "androidx/lifecycle/ReportFragment",
"android/arch/persistence/room/parser/SQLiteParser": "androidx/room/parser/SQLiteParser",
"android/arch/persistence/room/parser/SQLiteListener": "androidx/room/parser/SQLiteListener",
"android/arch/persistence/room/parser/SQLiteVisitor": "androidx/room/parser/SQLiteVisitor",
@@ -3532,6 +3228,7 @@
"android/arch/persistence/room/vo/InsertionMethod": "androidx/room/vo/InsertionMethod",
"android/arch/persistence/room/vo/DaoMethod": "androidx/room/vo/DaoMethod",
"android/arch/persistence/room/ext/SupportDbTypeNames": "androidx/room/ext/SupportDbTypeNames",
+ "android/arch/persistence/room/RoomMasterTable": "androidx/room/RoomMasterTable",
"android/arch/persistence/room/RoomProcessor": "androidx/room/RoomProcessor",
"android/arch/persistence/room/writer/EntityInsertionAdapterWriter": "androidx/room/writer/EntityInsertionAdapterWriter",
"android/arch/persistence/room/writer/TableInfoValidationWriter": "androidx/room/writer/TableInfoValidationWriter",
@@ -3550,6 +3247,7 @@
"android/arch/persistence/room/Dao": "androidx/room/Dao",
"android/arch/persistence/room/processor/CustomConverterProcessor": "androidx/room/processor/CustomConverterProcessor",
"android/arch/persistence/room/processor/cache/Cache": "androidx/room/processor/cache/Cache",
+ "android/arch/persistence/room/ColumnInfo": "androidx/room/ColumnInfo",
"android/arch/persistence/room/Embedded": "androidx/room/Embedded",
"android/arch/persistence/room/Relation": "androidx/room/Relation",
"android/arch/persistence/room/Ignore": "androidx/room/Ignore",
@@ -3575,12 +3273,237 @@
"android/arch/persistence/room/TypeConverter": "androidx/room/TypeConverter",
"android/arch/persistence/room/TypeConverters": "androidx/room/TypeConverters",
"android/arch/persistence/room/PrimaryKey": "androidx/room/PrimaryKey",
+ "android/support/design/resources/TextAppearance": "android/support/design/resources/TextAppearance",
+ "android/support/design/resources/R": "android/support/design/resources/R",
+ "android/support/annotation/FontRes": "androidx/annotation/FontRes",
+ "android/support/v13/view/DragAndDropPermissionsCompat": "androidx/core/view/DragAndDropPermissionsCompat",
+ "android/support/v13/view/DragStartHelper": "androidx/core/view/DragStartHelper",
+ "android/support/v13/view/inputmethod/EditorInfoCompat": "androidx/core/view/inputmethod/EditorInfoCompat",
+ "android/support/v13/view/inputmethod/InputConnectionCompat": "androidx/core/view/inputmethod/InputConnectionCompat",
+ "android/support/v13/view/inputmethod/InputContentInfoCompat": "androidx/core/view/inputmethod/InputContentInfoCompat",
+ "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": "androidx/core/accessibilityservice/AccessibilityServiceInfoCompat",
+ "android/support/v4/app/ActivityOptionsCompat": "androidx/core/app/ActivityOptionsCompat",
+ "android/support/v4/app/AlarmManagerCompat": "androidx/core/app/AlarmManagerCompat",
+ "android/support/v4/app/AppLaunchChecker": "androidx/core/app/AppLaunchChecker",
+ "android/support/v4/app/AppOpsManagerCompat": "androidx/core/app/AppOpsManagerCompat",
+ "android/support/v4/app/FrameMetricsAggregator": "androidx/core/app/FrameMetricsAggregator",
+ "android/support/v4/app/INotificationSideChannel": "androidx/core/app/INotificationSideChannel",
+ "android/support/v4/app/JobIntentService": "androidx/core/app/JobIntentService",
+ "android/support/v4/app/NavUtils": "androidx/core/app/NavUtils",
+ "android/support/v4/app/RemoteInput": "androidx/core/app/RemoteInput",
+ "android/support/v4/app/NotificationCompatBuilder": "androidx/core/app/NotificationCompatBuilder",
+ "android/support/compat/R": "androidx/core/R",
+ "android/support/v4/text/BidiFormatter": "androidx/core/text/BidiFormatter",
+ "android/support/v4/app/NotificationCompatJellybean": "androidx/core/app/NotificationCompatJellybean",
+ "android/support/v4/app/NotificationCompatExtras": "androidx/core/app/NotificationCompatExtras",
+ "android/support/v4/app/NotificationCompatSideChannelService": "androidx/core/app/NotificationCompatSideChannelService",
+ "android/support/v4/app/NotificationManagerCompat": "androidx/core/app/NotificationManagerCompat",
+ "android/support/annotation/GuardedBy": "androidx/annotation/GuardedBy",
+ "android/support/v4/app/ServiceCompat": "androidx/core/app/ServiceCompat",
+ "android/support/v4/app/ShareCompat": "androidx/core/app/ShareCompat",
+ "android/support/v4/app/TaskStackBuilder": "androidx/core/app/TaskStackBuilder",
+ "android/support/v4/content/FileProvider": "androidx/core/content/FileProvider",
+ "android/support/v4/content/IntentCompat": "androidx/core/content/IntentCompat",
+ "android/support/v4/content/MimeTypeFilter": "androidx/core/content/MimeTypeFilter",
+ "android/support/v4/content/PermissionChecker": "androidx/core/content/PermissionChecker",
+ "android/support/v4/content/SharedPreferencesCompat": "androidx/core/content/SharedPreferencesCompat",
+ "android/support/v4/content/pm/ActivityInfoCompat": "androidx/core/content/pm/ActivityInfoCompat",
+ "android/support/v4/content/pm/ShortcutInfoCompat": "androidx/core/content/pm/ShortcutInfoCompat",
+ "android/support/v4/graphics/drawable/IconCompat": "androidx/core/graphics/drawable/IconCompat",
+ "android/support/v4/content/pm/ShortcutManagerCompat": "androidx/core/content/pm/ShortcutManagerCompat",
+ "android/support/v4/content/res/ConfigurationHelper": "androidx/core/content/res/ConfigurationHelper",
+ "android/support/v4/content/res/FontResourcesParserCompat": "androidx/core/content/res/FontResourcesParserCompat",
+ "android/support/v4/provider/FontRequest": "androidx/core/provider/FontRequest",
+ "android/support/annotation/ArrayRes": "androidx/annotation/ArrayRes",
+ "android/support/v4/provider/FontsContractCompat": "androidx/core/provider/FontsContractCompat",
+ "android/support/v4/graphics/TypefaceCompat": "androidx/core/graphics/TypefaceCompat",
+ "android/support/annotation/AnyRes": "androidx/annotation/AnyRes",
+ "android/support/v4/database/DatabaseUtilsCompat": "androidx/core/database/DatabaseUtilsCompat",
+ "android/support/v4/graphics/BitmapCompat": "androidx/core/graphics/BitmapCompat",
+ "android/support/v4/graphics/PaintCompat": "androidx/core/graphics/PaintCompat",
+ "android/support/v4/graphics/TypefaceCompatApi28Impl": "androidx/core/graphics/TypefaceCompatApi28Impl",
+ "android/support/v4/graphics/TypefaceCompatApi26Impl": "androidx/core/graphics/TypefaceCompatApi26Impl",
+ "android/support/v4/graphics/TypefaceCompatApi24Impl": "androidx/core/graphics/TypefaceCompatApi24Impl",
+ "android/support/v4/graphics/TypefaceCompatApi21Impl": "androidx/core/graphics/TypefaceCompatApi21Impl",
+ "android/support/v4/graphics/TypefaceCompatBaseImpl": "androidx/core/graphics/TypefaceCompatBaseImpl",
+ "android/support/v4/graphics/TypefaceCompatUtil": "androidx/core/graphics/TypefaceCompatUtil",
+ "android/support/v4/graphics/drawable/WrappedDrawable": "androidx/core/graphics/drawable/WrappedDrawable",
+ "android/support/v4/graphics/drawable/WrappedDrawableApi21": "androidx/core/graphics/drawable/WrappedDrawableApi21",
+ "android/support/v4/graphics/drawable/WrappedDrawableApi19": "androidx/core/graphics/drawable/WrappedDrawableApi19",
+ "android/support/v4/graphics/drawable/WrappedDrawableApi14": "androidx/core/graphics/drawable/WrappedDrawableApi14",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawable": "androidx/core/graphics/drawable/RoundedBitmapDrawable",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawable21": "androidx/core/graphics/drawable/RoundedBitmapDrawable21",
+ "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": "androidx/core/graphics/drawable/RoundedBitmapDrawableFactory",
+ "android/support/v4/hardware/fingerprint/FingerprintManagerCompat": "androidx/core/hardware/fingerprint/FingerprintManagerCompat",
+ "android/support/annotation/RequiresPermission": "androidx/annotation/RequiresPermission",
+ "android/support/v4/internal/view/SupportMenu": "androidx/core/internal/view/SupportMenu",
+ "android/support/v4/internal/view/SupportMenuItem": "androidx/core/internal/view/SupportMenuItem",
+ "android/support/v4/internal/view/SupportSubMenu": "androidx/core/internal/view/SupportSubMenu",
+ "android/support/v4/math/MathUtils": "androidx/core/math/MathUtils",
+ "android/support/v4/net/ConnectivityManagerCompat": "androidx/core/net/ConnectivityManagerCompat",
+ "android/support/v4/net/DatagramSocketWrapper": "androidx/core/net/DatagramSocketWrapper",
+ "android/support/v4/net/TrafficStatsCompat": "androidx/core/net/TrafficStatsCompat",
+ "android/support/v4/os/ConfigurationCompat": "androidx/core/os/ConfigurationCompat",
+ "android/support/v4/os/EnvironmentCompat": "androidx/core/os/EnvironmentCompat",
+ "android/support/v4/os/IResultReceiver": "androidx/core/os/IResultReceiver",
+ "android/support/v4/os/LocaleHelper": "androidx/core/os/LocaleHelper",
+ "android/support/v4/os/LocaleListInterface": "androidx/core/os/LocaleListInterface",
+ "android/support/v4/os/LocaleListHelper": "androidx/core/os/LocaleListHelper",
+ "android/support/annotation/Size": "androidx/annotation/Size",
+ "android/support/v4/os/ParcelableCompat": "androidx/core/os/ParcelableCompat",
+ "android/support/v4/os/ParcelableCompatCreatorCallbacks": "androidx/core/os/ParcelableCompatCreatorCallbacks",
+ "android/support/v4/os/UserManagerCompat": "androidx/core/os/UserManagerCompat",
+ "android/support/v4/provider/SelfDestructiveThread": "androidx/core/provider/SelfDestructiveThread",
+ "android/support/v4/text/TextUtilsCompat": "androidx/core/text/TextUtilsCompat",
+ "android/support/v4/text/ICUCompat": "androidx/core/text/ICUCompat",
+ "android/support/v4/text/util/FindAddress": "androidx/core/text/util/FindAddress",
+ "android/support/v4/text/util/LinkifyCompat": "androidx/core/text/util/LinkifyCompat",
+ "android/support/v4/util/PatternsCompat": "androidx/core/util/PatternsCompat",
+ "android/support/v4/util/AtomicFile": "androidx/core/util/AtomicFile",
+ "android/support/v4/util/LogWriter": "androidx/core/util/LogWriter",
+ "android/support/v4/view/InputDeviceCompat": "androidx/core/view/InputDeviceCompat",
+ "android/support/v4/view/LayoutInflaterCompat": "androidx/core/view/LayoutInflaterCompat",
+ "android/support/v4/view/LayoutInflaterFactory": "androidx/core/view/LayoutInflaterFactory",
+ "android/support/v4/view/MenuCompat": "androidx/core/view/MenuCompat",
+ "android/support/v4/view/MenuItemCompat": "androidx/core/view/MenuItemCompat",
+ "android/support/v4/view/NestedScrollingChild": "androidx/core/view/NestedScrollingChild",
+ "android/support/v4/view/NestedScrollingParent2": "androidx/core/view/NestedScrollingParent2",
+ "android/support/v4/view/ScaleGestureDetectorCompat": "androidx/core/view/ScaleGestureDetectorCompat",
+ "android/support/v4/view/VelocityTrackerCompat": "androidx/core/view/VelocityTrackerCompat",
+ "android/support/v4/view/ViewPropertyAnimatorCompat": "androidx/core/view/ViewPropertyAnimatorCompat",
+ "android/support/v4/view/ViewGroupCompat": "androidx/core/view/ViewGroupCompat",
+ "android/support/v4/view/ViewPropertyAnimatorListener": "androidx/core/view/ViewPropertyAnimatorListener",
+ "android/support/v4/view/ViewPropertyAnimatorUpdateListener": "androidx/core/view/ViewPropertyAnimatorUpdateListener",
+ "android/support/v4/view/ViewPropertyAnimatorListenerAdapter": "androidx/core/view/ViewPropertyAnimatorListenerAdapter",
+ "android/support/v4/view/WindowCompat": "androidx/core/view/WindowCompat",
+ "android/support/v4/view/accessibility/AccessibilityManagerCompat": "androidx/core/view/accessibility/AccessibilityManagerCompat",
+ "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": "androidx/core/view/accessibility/AccessibilityWindowInfoCompat",
+ "android/support/v4/view/animation/PathInterpolatorApi14": "androidx/core/view/animation/PathInterpolatorApi14",
+ "android/support/v4/view/animation/PathInterpolatorCompat": "androidx/core/view/animation/PathInterpolatorCompat",
+ "android/support/v4/widget/AutoScrollHelper": "androidx/core/widget/AutoScrollHelper",
+ "android/support/v4/widget/AutoSizeableTextView": "androidx/core/widget/AutoSizeableTextView",
+ "android/support/v4/widget/CompoundButtonCompat": "androidx/core/widget/CompoundButtonCompat",
+ "android/support/v4/widget/TintableCompoundButton": "androidx/core/widget/TintableCompoundButton",
+ "android/support/v4/widget/ContentLoadingProgressBar": "androidx/core/widget/ContentLoadingProgressBar",
+ "android/support/v4/widget/ImageViewCompat": "androidx/core/widget/ImageViewCompat",
+ "android/support/v4/widget/ListPopupWindowCompat": "androidx/core/widget/ListPopupWindowCompat",
+ "android/support/v4/widget/ListViewAutoScrollHelper": "androidx/core/widget/ListViewAutoScrollHelper",
+ "android/support/v4/widget/ListViewCompat": "androidx/core/widget/ListViewCompat",
+ "android/support/v4/widget/PopupMenuCompat": "androidx/core/widget/PopupMenuCompat",
+ "android/support/v4/widget/PopupWindowCompat": "androidx/core/widget/PopupWindowCompat",
+ "android/support/v4/widget/ScrollerCompat": "androidx/core/widget/ScrollerCompat",
"android/support/coordinatorlayout/R": "androidx/coordinatorlayout/R",
"android/support/v4/widget/DirectedAcyclicGraph": "androidx/coordinatorlayout/widget/DirectedAcyclicGraph",
"android/support/v4/widget/ViewGroupUtils": "androidx/coordinatorlayout/widget/ViewGroupUtils",
- "android/support/v4/widget/FocusStrategy": "androidx/customview/widget/FocusStrategy",
- "android/support/v7/widget/GridLayout": "androidx/gridlayout/widget/GridLayout",
- "android/support/v7/gridlayout/R": "androidx/gridlayout/R",
+ "android/arch/lifecycle/EmptyActivityLifecycleCallbacks": "androidx/lifecycle/EmptyActivityLifecycleCallbacks",
+ "android/arch/lifecycle/HolderFragment": "androidx/lifecycle/HolderFragment",
+ "android/arch/lifecycle/LifecycleDispatcher": "androidx/lifecycle/LifecycleDispatcher",
+ "android/arch/lifecycle/LifecycleService": "androidx/lifecycle/LifecycleService",
+ "android/arch/lifecycle/ServiceLifecycleDispatcher": "androidx/lifecycle/ServiceLifecycleDispatcher",
+ "android/arch/lifecycle/ProcessLifecycleOwner": "androidx/lifecycle/ProcessLifecycleOwner",
+ "android/arch/lifecycle/ProcessLifecycleOwnerInitializer": "androidx/lifecycle/ProcessLifecycleOwnerInitializer",
+ "android/arch/lifecycle/ViewModelProviders": "androidx/lifecycle/ViewModelProviders",
+ "android/arch/lifecycle/ViewModelStores": "androidx/lifecycle/ViewModelStores",
+ "android/support/animation/AnimationHandler": "androidx/dynamicanimation/animation/AnimationHandler",
+ "android/support/animation/DynamicAnimation": "androidx/dynamicanimation/animation/DynamicAnimation",
+ "android/support/animation/FloatPropertyCompat": "androidx/dynamicanimation/animation/FloatPropertyCompat",
+ "android/support/animation/FloatValueHolder": "androidx/dynamicanimation/animation/FloatValueHolder",
+ "android/support/animation/FlingAnimation": "androidx/dynamicanimation/animation/FlingAnimation",
+ "android/support/animation/Force": "androidx/dynamicanimation/animation/Force",
+ "android/support/animation/SpringAnimation": "androidx/dynamicanimation/animation/SpringAnimation",
+ "android/support/animation/SpringForce": "androidx/dynamicanimation/animation/SpringForce",
+ "android/support/design/transformation/ExpandableBehavior": "android/support/design/transformation/ExpandableBehavior",
+ "android/support/design/transformation/ExpandableTransformationBehavior": "android/support/design/transformation/ExpandableTransformationBehavior",
+ "android/support/design/transformation/FabTransformationBehavior": "android/support/design/transformation/FabTransformationBehavior",
+ "android/support/design/transformation/R": "android/support/design/transformation/R",
+ "android/support/design/transformation/TransformationChildLayout": "android/support/design/transformation/TransformationChildLayout",
+ "android/support/design/transformation/TransformationChildCard": "android/support/design/transformation/TransformationChildCard",
+ "android/support/design/transformation/FabTransformationScrimBehavior": "android/support/design/transformation/FabTransformationScrimBehavior",
+ "android/support/design/transformation/FabTransformationSheetBehavior": "android/support/design/transformation/FabTransformationSheetBehavior",
+ "android/support/design/circularreveal/cardview/CircularRevealCardView": "android/support/design/circularreveal/cardview/CircularRevealCardView",
+ "android/support/content/ContentPager": "androidx/contentpager/content/ContentPager",
+ "android/support/content/Query": "androidx/contentpager/content/Query",
+ "android/support/content/InMemoryCursor": "androidx/contentpager/content/InMemoryCursor",
+ "android/support/content/LoaderQueryRunner": "androidx/contentpager/content/LoaderQueryRunner",
+ "android/support/v4/widget/CursorAdapter": "androidx/cursoradapter/widget/CursorAdapter",
+ "android/support/v4/widget/CursorFilter": "androidx/cursoradapter/widget/CursorFilter",
+ "android/support/v4/widget/ResourceCursorAdapter": "androidx/cursoradapter/widget/ResourceCursorAdapter",
+ "android/support/v4/widget/SimpleCursorAdapter": "androidx/cursoradapter/widget/SimpleCursorAdapter",
+ "android/support/v4/app/ActionBarDrawerToggle": "androidx/legacy/app/ActionBarDrawerToggle",
+ "android/arch/lifecycle/ClassesInfoCache": "androidx/lifecycle/ClassesInfoCache",
+ "android/arch/lifecycle/FullLifecycleObserver": "androidx/lifecycle/FullLifecycleObserver",
+ "android/arch/lifecycle/FullLifecycleObserverAdapter": "androidx/lifecycle/FullLifecycleObserverAdapter",
+ "android/arch/lifecycle/SingleGeneratedAdapterObserver": "androidx/lifecycle/SingleGeneratedAdapterObserver",
+ "android/arch/lifecycle/CompositeGeneratedAdaptersObserver": "androidx/lifecycle/CompositeGeneratedAdaptersObserver",
+ "android/arch/lifecycle/ReflectiveGenericLifecycleObserver": "androidx/lifecycle/ReflectiveGenericLifecycleObserver",
+ "android/support/v4/util/MapCollections": "androidx/collection/MapCollections",
+ "android/support/v4/util/ContainerHelpers": "androidx/collection/ContainerHelpers",
+ "android/support/design/theme/MaterialComponentsViewInflater": "android/support/design/theme/MaterialComponentsViewInflater",
+ "android/support/v7/app/AppCompatViewInflater": "androidx/appcompat/app/AppCompatViewInflater",
+ "android/support/annotation/Keep": "androidx/annotation/Keep",
+ "android/arch/paging/PageResult": "androidx/paging/PageResult",
+ "android/arch/paging/ListDataSource": "androidx/paging/ListDataSource",
+ "android/arch/paging/PositionalDataSource": "androidx/paging/PositionalDataSource",
+ "android/arch/paging/WrapperItemKeyedDataSource": "androidx/paging/WrapperItemKeyedDataSource",
+ "android/arch/paging/DataSource": "androidx/paging/DataSource",
+ "android/arch/paging/PageKeyedDataSource": "androidx/paging/PageKeyedDataSource",
+ "android/arch/paging/ContiguousDataSource": "androidx/paging/ContiguousDataSource",
+ "android/arch/paging/WrapperPageKeyedDataSource": "androidx/paging/WrapperPageKeyedDataSource",
+ "android/arch/paging/ItemKeyedDataSource": "androidx/paging/ItemKeyedDataSource",
+ "android/arch/paging/TiledPagedList": "androidx/paging/TiledPagedList",
+ "android/arch/paging/PagedList": "androidx/paging/PagedList",
+ "android/arch/paging/PagedStorage": "androidx/paging/PagedStorage",
+ "android/support/annotation/AnyThread": "androidx/annotation/AnyThread",
+ "android/arch/paging/TiledDataSource": "androidx/paging/TiledDataSource",
+ "android/arch/paging/WrapperPositionalDataSource": "androidx/paging/WrapperPositionalDataSource",
+ "android/arch/paging/ContiguousPagedList": "androidx/paging/ContiguousPagedList",
+ "android/arch/paging/SnapshotPagedList": "androidx/paging/SnapshotPagedList",
+ "android/support/design/shape/CornerTreatment": "android/support/design/shape/CornerTreatment",
+ "android/support/design/shape/ShapePath": "android/support/design/shape/ShapePath",
+ "android/support/design/shape/CutCornerTreatment": "android/support/design/shape/CutCornerTreatment",
+ "android/support/design/shape/EdgeTreatment": "android/support/design/shape/EdgeTreatment",
+ "android/support/design/shape/InterpolateOnScrollPositionChangeHelper": "android/support/design/shape/InterpolateOnScrollPositionChangeHelper",
+ "android/support/design/shape/MaterialShapeDrawable": "android/support/design/shape/MaterialShapeDrawable",
+ "android/support/design/shape/ShapePathModel": "android/support/design/shape/ShapePathModel",
+ "android/support/design/shape/RoundedCornerTreatment": "android/support/design/shape/RoundedCornerTreatment",
+ "android/support/design/shape/TriangleEdgeTreatment": "android/support/design/shape/TriangleEdgeTreatment",
+ "android/support/design/bottomappbar/BottomAppBar": "android/support/design/bottomappbar/BottomAppBar",
+ "android/support/design/bottomappbar/BottomAppBarTopEdgeTreatment": "android/support/design/bottomappbar/BottomAppBarTopEdgeTreatment",
+ "android/support/v7/widget/ActionMenuView": "androidx/appcompat/widget/ActionMenuView",
+ "android/support/design/bottomappbar/R": "android/support/design/bottomappbar/R",
+ "android/support/annotation/MenuRes": "androidx/annotation/MenuRes",
+ "android/arch/persistence/room/testing/MigrationTestHelper": "androidx/room/testing/MigrationTestHelper",
+ "android/arch/persistence/db/SupportSQLiteDatabase": "androidx/sqlite/db/SupportSQLiteDatabase",
+ "android/arch/persistence/room/util/TableInfo": "androidx/room/util/TableInfo",
+ "android/arch/persistence/room/RoomOpenHelper": "androidx/room/RoomOpenHelper",
+ "android/arch/persistence/db/SupportSQLiteOpenHelper": "androidx/sqlite/db/SupportSQLiteOpenHelper",
+ "android/arch/persistence/room/RoomDatabase": "androidx/room/RoomDatabase",
+ "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory": "androidx/sqlite/db/framework/FrameworkSQLiteOpenHelperFactory",
+ "android/arch/persistence/room/DatabaseConfiguration": "androidx/room/DatabaseConfiguration",
+ "android/arch/persistence/room/migration/Migration": "androidx/room/migration/Migration",
+ "android/support/v7/graphics/ColorCutQuantizer": "androidx/palette/graphics/ColorCutQuantizer",
+ "android/support/v7/graphics/Target": "androidx/palette/graphics/Target",
+ "android/arch/persistence/room/EmptyResultSetException": "androidx/room/EmptyResultSetException",
+ "android/arch/persistence/room/RxRoom": "androidx/room/RxRoom",
+ "android/arch/persistence/room/InvalidationTracker": "androidx/room/InvalidationTracker",
+ "android/support/v4/view/AsyncLayoutInflater": "androidx/asynclayoutinflater/view/AsyncLayoutInflater",
+ "android/arch/persistence/room/ForeignKey": "androidx/room/ForeignKey",
+ "android/arch/persistence/room/RoomWarnings": "androidx/room/RoomWarnings",
+ "android/arch/persistence/room/Index": "androidx/room/Index",
+ "android/arch/persistence/room/OnConflictStrategy": "androidx/room/OnConflictStrategy",
+ "android/arch/lifecycle/AndroidViewModel": "androidx/lifecycle/AndroidViewModel",
+ "android/support/v4/widget/CircleImageView": "androidx/swiperefreshlayout/widget/CircleImageView",
+ "android/support/v4/widget/SwipeRefreshLayout": "androidx/swiperefreshlayout/widget/SwipeRefreshLayout",
+ "android/support/v4/view/PagerTabStrip": "androidx/viewpager/widget/PagerTabStrip",
+ "android/support/v4/view/PagerTitleStrip": "androidx/viewpager/widget/PagerTitleStrip",
+ "android/support/design/chip/Chip": "android/support/design/chip/Chip",
+ "android/support/design/chip/ChipDrawable": "android/support/design/chip/ChipDrawable",
+ "android/support/design/chip/R": "android/support/design/chip/R",
+ "android/support/v7/widget/AppCompatCheckBox": "androidx/appcompat/widget/AppCompatCheckBox",
+ "android/support/annotation/XmlRes": "androidx/annotation/XmlRes",
+ "android/support/design/canvas/CanvasCompat": "android/support/design/canvas/CanvasCompat",
+ "android/support/design/drawable/DrawableUtils": "android/support/design/drawable/DrawableUtils",
+ "android/support/design/chip/ChipGroup": "android/support/design/chip/ChipGroup",
"android/support/media/tv/BasePreviewProgram": "androidx/tvprovider/media/tv/BasePreviewProgram",
"android/support/media/tv/BaseProgram": "androidx/tvprovider/media/tv/BaseProgram",
"android/support/media/tv/TvContractCompat": "androidx/tvprovider/media/tv/TvContractCompat",
@@ -3593,13 +3516,6 @@
"android/support/media/tv/PreviewProgram": "androidx/tvprovider/media/tv/PreviewProgram",
"android/support/media/tv/WatchNextProgram": "androidx/tvprovider/media/tv/WatchNextProgram",
"android/support/media/tv/Program": "androidx/tvprovider/media/tv/Program",
- "android/support/v13/app/ActivityCompat": "androidx/legacy/app/ActivityCompat",
- "android/support/v13/app/FragmentCompat": "androidx/legacy/app/FragmentCompat",
- "android/support/v13/app/FragmentPagerAdapter": "androidx/legacy/app/FragmentPagerAdapter",
- "android/support/v13/app/FragmentStatePagerAdapter": "androidx/legacy/app/FragmentStatePagerAdapter",
- "android/support/v13/app/FragmentTabHost": "androidx/legacy/app/FragmentTabHost",
- "android/support/v13/view/ViewCompat": "androidx/legacy/view/ViewCompat",
- "android/support/v4/content/WakefulBroadcastReceiver": "androidx/legacy/content/WakefulBroadcastReceiver",
"android/support/v7/view/ActionMode": "androidx/appcompat/view/ActionMode",
"android/support/v7/app/ActionBarDrawerToggle": "androidx/appcompat/app/ActionBarDrawerToggle",
"android/support/v7/graphics/drawable/DrawerArrowDrawable": "androidx/appcompat/graphics/drawable/DrawerArrowDrawable",
@@ -3631,6 +3547,7 @@
"android/support/v7/view/StandaloneActionMode": "androidx/appcompat/view/StandaloneActionMode",
"android/support/v7/widget/TintContextWrapper": "androidx/appcompat/widget/TintContextWrapper",
"android/support/v7/widget/AppCompatImageView": "androidx/appcompat/widget/AppCompatImageView",
+ "android/support/v7/widget/AppCompatButton": "androidx/appcompat/widget/AppCompatButton",
"android/support/v7/widget/AppCompatSpinner": "androidx/appcompat/widget/AppCompatSpinner",
"android/support/v7/widget/AppCompatRadioButton": "androidx/appcompat/widget/AppCompatRadioButton",
"android/support/v7/widget/AppCompatCheckedTextView": "androidx/appcompat/widget/AppCompatCheckedTextView",
@@ -3686,6 +3603,7 @@
"android/support/v7/widget/AppCompatHintHelper": "androidx/appcompat/widget/AppCompatHintHelper",
"android/support/v7/widget/TintInfo": "androidx/appcompat/widget/TintInfo",
"android/support/v7/widget/AppCompatCompoundButtonHelper": "androidx/appcompat/widget/AppCompatCompoundButtonHelper",
+ "android/support/graphics/drawable/AnimatedVectorDrawableCompat": "androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat",
"android/support/v7/widget/ThemeUtils": "androidx/appcompat/widget/ThemeUtils",
"android/support/v7/widget/WithHint": "androidx/appcompat/widget/WithHint",
"android/support/v7/widget/AppCompatPopupWindow": "androidx/appcompat/widget/AppCompatPopupWindow",
@@ -3708,23 +3626,115 @@
"android/support/v7/widget/TintResources": "androidx/appcompat/widget/TintResources",
"android/support/v7/widget/TooltipCompatHandler": "androidx/appcompat/widget/TooltipCompatHandler",
"android/support/v7/widget/TooltipPopup": "androidx/appcompat/widget/TooltipPopup",
+ "android/support/percent/PercentFrameLayout": "androidx/percentlayout/widget/PercentFrameLayout",
+ "android/support/percent/PercentLayoutHelper": "androidx/percentlayout/widget/PercentLayoutHelper",
+ "android/support/percent/R": "androidx/percentlayout/R",
+ "android/support/percent/PercentRelativeLayout": "androidx/percentlayout/widget/PercentRelativeLayout",
+ "android/support/v14/preference/EditTextPreferenceDialogFragment": "androidx/preference/EditTextPreferenceDialogFragment",
+ "android/support/v14/preference/PreferenceDialogFragment": "androidx/preference/PreferenceDialogFragment",
+ "android/support/v7/preference/EditTextPreference": "androidx/preference/EditTextPreference",
+ "android/support/v14/preference/ListPreferenceDialogFragment": "androidx/preference/ListPreferenceDialogFragment",
+ "android/support/v7/preference/internal/AbstractMultiSelectListPreference": "androidx/preference/internal/AbstractMultiSelectListPreference",
+ "android/support/v7/preference/R": "androidx/preference/R",
+ "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": "androidx/preference/MultiSelectListPreferenceDialogFragment",
+ "android/support/v7/preference/PreferenceGroup": "androidx/preference/PreferenceGroup",
+ "android/support/v7/preference/PreferenceViewHolder": "androidx/preference/PreferenceViewHolder",
+ "android/support/v7/preference/PreferenceManager": "androidx/preference/PreferenceManager",
+ "android/support/v7/preference/PreferenceGroupAdapter": "androidx/preference/PreferenceGroupAdapter",
+ "android/support/v14/preference/SwitchPreference": "androidx/preference/SwitchPreference",
+ "android/support/v7/preference/TwoStatePreference": "androidx/preference/TwoStatePreference",
+ "android/support/v7/internal/widget/PreferenceImageView": "androidx/preference/internal/PreferenceImageView",
+ "android/support/v7/preference/AndroidResources": "androidx/preference/AndroidResources",
+ "android/support/v7/preference/CheckBoxPreference": "androidx/preference/CheckBoxPreference",
+ "android/support/v7/preference/CollapsiblePreferenceGroupController": "androidx/preference/CollapsiblePreferenceGroupController",
+ "android/support/v7/preference/DropDownPreference": "androidx/preference/DropDownPreference",
+ "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": "androidx/preference/EditTextPreferenceDialogFragmentCompat",
+ "android/support/v7/preference/PreferenceDialogFragmentCompat": "androidx/preference/PreferenceDialogFragmentCompat",
+ "android/support/v7/preference/ListPreferenceDialogFragmentCompat": "androidx/preference/ListPreferenceDialogFragmentCompat",
+ "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat",
+ "android/support/v7/preference/PreferenceDataStore": "androidx/preference/PreferenceDataStore",
+ "android/support/v7/preference/PreferenceCategory": "androidx/preference/PreferenceCategory",
+ "android/support/v7/preference/PreferenceFragmentCompat": "androidx/preference/PreferenceFragmentCompat",
+ "android/support/v7/preference/PreferenceInflater": "androidx/preference/PreferenceInflater",
+ "android/support/v7/preference/SeekBarPreference": "androidx/preference/SeekBarPreference",
+ "android/support/v7/preference/SwitchPreferenceCompat": "androidx/preference/SwitchPreferenceCompat",
+ "android/support/v7/preference/UnPressableLinearLayout": "androidx/preference/UnPressableLinearLayout",
+ "android/support/v4/app/BackStackRecord": "androidx/fragment/app/BackStackRecord",
+ "android/support/v4/app/FragmentManagerImpl": "androidx/fragment/app/FragmentManagerImpl",
+ "android/support/v4/app/FragmentHostCallback": "androidx/fragment/app/FragmentHostCallback",
+ "android/support/v4/app/FragmentTransition": "androidx/fragment/app/FragmentTransition",
+ "android/support/v4/app/BackStackState": "androidx/fragment/app/BackStackState",
+ "android/support/v4/app/BaseFragmentActivityApi14": "androidx/fragment/app/BaseFragmentActivityApi14",
+ "android/support/v4/app/BaseFragmentActivityApi16": "androidx/fragment/app/BaseFragmentActivityApi16",
+ "android/support/v4/app/FragmentContainer": "androidx/fragment/app/FragmentContainer",
+ "android/support/v4/app/FragmentManagerNonConfig": "androidx/fragment/app/FragmentManagerNonConfig",
+ "android/support/v4/app/SuperNotCalledException": "androidx/fragment/app/SuperNotCalledException",
+ "android/support/v4/app/FragmentController": "androidx/fragment/app/FragmentController",
+ "android/support/v4/app/FragmentState": "androidx/fragment/app/FragmentState",
+ "android/support/v4/app/FragmentManagerState": "androidx/fragment/app/FragmentManagerState",
+ "android/support/v4/app/FragmentPagerAdapter": "androidx/fragment/app/FragmentPagerAdapter",
+ "android/support/v4/app/FragmentStatePagerAdapter": "androidx/fragment/app/FragmentStatePagerAdapter",
+ "android/support/v4/app/FragmentTabHost": "androidx/fragment/app/FragmentTabHost",
+ "android/support/annotation/AnimRes": "androidx/annotation/AnimRes",
+ "android/support/v4/app/OneShotPreDrawListener": "androidx/fragment/app/OneShotPreDrawListener",
+ "android/support/v4/app/FragmentTransitionCompat21": "androidx/fragment/app/FragmentTransitionCompat21",
+ "android/support/v4/app/ListFragment": "androidx/fragment/app/ListFragment",
"android/arch/core/executor/JunitTaskExecutorRule": "androidx/arch/core/executor/JunitTaskExecutorRule",
"android/arch/core/executor/TaskExecutorWithFakeMainThread": "androidx/arch/core/executor/TaskExecutorWithFakeMainThread",
"android/arch/core/executor/TaskExecutor": "androidx/arch/core/executor/TaskExecutor",
"android/arch/core/executor/testing/CountingTaskExecutorRule": "androidx/arch/core/executor/testing/CountingTaskExecutorRule",
"android/arch/core/executor/DefaultTaskExecutor": "androidx/arch/core/executor/DefaultTaskExecutor",
"android/arch/core/executor/testing/InstantTaskExecutorRule": "androidx/arch/core/executor/testing/InstantTaskExecutorRule",
- "android/support/text/emoji/widget/EmojiAppCompatButton": "androidx/emoji/widget/EmojiAppCompatButton",
- "android/support/text/emoji/widget/EmojiAppCompatEditText": "androidx/emoji/widget/EmojiAppCompatEditText",
- "android/support/text/emoji/widget/EmojiAppCompatTextView": "androidx/emoji/widget/EmojiAppCompatTextView",
- "android/support/design/card/MaterialCardView": "android/support/design/card/MaterialCardView",
- "android/support/design/card/R": "android/support/design/card/R",
- "android/support/design/card/MaterialCardViewHelper": "android/support/design/card/MaterialCardViewHelper",
- "android/arch/lifecycle/ClassesInfoCache": "androidx/lifecycle/ClassesInfoCache",
- "android/arch/lifecycle/FullLifecycleObserverAdapter": "androidx/lifecycle/FullLifecycleObserverAdapter",
- "android/arch/lifecycle/SingleGeneratedAdapterObserver": "androidx/lifecycle/SingleGeneratedAdapterObserver",
- "android/arch/lifecycle/CompositeGeneratedAdaptersObserver": "androidx/lifecycle/CompositeGeneratedAdaptersObserver",
- "android/arch/lifecycle/ReflectiveGenericLifecycleObserver": "androidx/lifecycle/ReflectiveGenericLifecycleObserver",
+ "android/support/multidex/MultiDex": "androidx/multidex/MultiDex",
+ "android/arch/paging/AsyncPagedListDiffer": "androidx/paging/AsyncPagedListDiffer",
+ "android/arch/paging/PagedStorageDiffHelper": "androidx/paging/PagedStorageDiffHelper",
+ "android/arch/paging/LivePagedListBuilder": "androidx/paging/LivePagedListBuilder",
+ "android/arch/paging/LivePagedListProvider": "androidx/paging/LivePagedListProvider",
+ "android/arch/paging/PagedListAdapter": "androidx/paging/PagedListAdapter",
+ "android/arch/lifecycle/LiveDataReactiveStreams": "androidx/lifecycle/LiveDataReactiveStreams",
+ "android/support/design/circularreveal/coordinatorlayout/CircularRevealCoordinatorLayout": "android/support/design/circularreveal/coordinatorlayout/CircularRevealCoordinatorLayout",
+ "android/support/multidex/ZipUtil": "androidx/multidex/ZipUtil",
+ "android/support/multidex/MultiDexExtractor": "androidx/multidex/MultiDexExtractor",
+ "android/support/multidex/MultiDexApplication": "androidx/multidex/MultiDexApplication",
+ "android/arch/persistence/room/EntityDeletionOrUpdateAdapter": "androidx/room/EntityDeletionOrUpdateAdapter",
+ "android/arch/persistence/room/SharedSQLiteStatement": "androidx/room/SharedSQLiteStatement",
+ "android/arch/persistence/db/SupportSQLiteStatement": "androidx/sqlite/db/SupportSQLiteStatement",
+ "android/arch/persistence/room/EntityInsertionAdapter": "androidx/room/EntityInsertionAdapter",
+ "android/arch/persistence/room/Room": "androidx/room/Room",
+ "android/arch/persistence/db/SimpleSQLiteQuery": "androidx/sqlite/db/SimpleSQLiteQuery",
+ "android/arch/persistence/db/SupportSQLiteQuery": "androidx/sqlite/db/SupportSQLiteQuery",
+ "android/arch/persistence/db/SupportSQLiteProgram": "androidx/sqlite/db/SupportSQLiteProgram",
+ "android/arch/persistence/room/paging/LimitOffsetDataSource": "androidx/room/paging/LimitOffsetDataSource",
+ "android/arch/persistence/room/util/StringUtil": "androidx/room/util/StringUtil",
+ "android/arch/lifecycle/DefaultLifecycleObserver": "androidx/lifecycle/DefaultLifecycleObserver",
+ "android/support/design/button/MaterialButton": "android/support/design/button/MaterialButton",
+ "android/support/design/button/R": "android/support/design/button/R",
+ "android/support/design/button/MaterialButtonHelper": "android/support/design/button/MaterialButtonHelper",
+ "android/support/design/button/MaterialButtonBackgroundDrawable": "android/support/design/button/MaterialButtonBackgroundDrawable",
+ "android/support/text/emoji/EmojiProcessor": "androidx/emoji/text/EmojiProcessor",
+ "android/support/text/emoji/EmojiMetadata": "androidx/emoji/text/EmojiMetadata",
+ "android/support/text/emoji/EmojiSpan": "androidx/emoji/text/EmojiSpan",
+ "android/support/text/emoji/TypefaceEmojiSpan": "androidx/emoji/text/TypefaceEmojiSpan",
+ "android/support/annotation/CheckResult": "androidx/annotation/CheckResult",
+ "android/support/text/emoji/widget/SpannableBuilder": "androidx/emoji/widget/SpannableBuilder",
+ "android/support/text/emoji/FontRequestEmojiCompatConfig": "androidx/emoji/text/FontRequestEmojiCompatConfig",
+ "android/support/text/emoji/MetadataListReader": "androidx/emoji/text/MetadataListReader",
+ "android/support/text/emoji/widget/EditTextAttributeHelper": "androidx/emoji/widget/EditTextAttributeHelper",
+ "android/support/text/emoji/R": "androidx/emoji/R",
+ "android/support/text/emoji/widget/EmojiButton": "androidx/emoji/widget/EmojiButton",
+ "android/support/text/emoji/widget/EmojiTextViewHelper": "androidx/emoji/widget/EmojiTextViewHelper",
+ "android/support/text/emoji/widget/EmojiEditText": "androidx/emoji/widget/EmojiEditText",
+ "android/support/text/emoji/widget/EmojiEditTextHelper": "androidx/emoji/widget/EmojiEditTextHelper",
+ "android/support/text/emoji/widget/EmojiTextWatcher": "androidx/emoji/widget/EmojiTextWatcher",
+ "android/support/text/emoji/widget/EmojiEditableFactory": "androidx/emoji/widget/EmojiEditableFactory",
+ "android/support/text/emoji/widget/EmojiKeyListener": "androidx/emoji/widget/EmojiKeyListener",
+ "android/support/text/emoji/widget/EmojiInputConnection": "androidx/emoji/widget/EmojiInputConnection",
+ "android/support/text/emoji/widget/EmojiExtractEditText": "androidx/emoji/widget/EmojiExtractEditText",
+ "android/support/text/emoji/widget/EmojiExtractTextLayout": "androidx/emoji/widget/EmojiExtractTextLayout",
+ "android/support/text/emoji/widget/ExtractButtonCompat": "androidx/emoji/widget/ExtractButtonCompat",
+ "android/support/text/emoji/widget/EmojiInputFilter": "androidx/emoji/widget/EmojiInputFilter",
+ "android/support/text/emoji/widget/EmojiTextView": "androidx/emoji/widget/EmojiTextView",
+ "android/support/text/emoji/widget/EmojiTransformationMethod": "androidx/emoji/widget/EmojiTransformationMethod",
"android/support/customtabs/CustomTabsCallback": "androidx/browser/customtabs/CustomTabsCallback",
"android/support/customtabs/CustomTabsClient": "androidx/browser/customtabs/CustomTabsClient",
"android/support/customtabs/CustomTabsServiceConnection": "androidx/browser/customtabs/CustomTabsServiceConnection",
@@ -3739,34 +3749,38 @@
"android/support/customtabs/PostMessageServiceConnection": "androidx/browser/customtabs/PostMessageServiceConnection",
"android/support/customtabs/TrustedWebUtils": "androidx/browser/customtabs/TrustedWebUtils",
"android/support/customtabs/R": "androidx/browser/R",
- "android/arch/lifecycle/AndroidViewModel": "androidx/lifecycle/AndroidViewModel",
- "android/support/design/circularreveal/coordinatorlayout/CircularRevealCoordinatorLayout": "android/support/design/circularreveal/coordinatorlayout/CircularRevealCoordinatorLayout",
- "android/support/percent/PercentFrameLayout": "androidx/percentlayout/widget/PercentFrameLayout",
- "android/support/percent/PercentLayoutHelper": "androidx/percentlayout/widget/PercentLayoutHelper",
- "android/support/percent/R": "androidx/percentlayout/R",
- "android/support/percent/PercentRelativeLayout": "androidx/percentlayout/widget/PercentRelativeLayout",
+ "android/arch/persistence/db/framework/FrameworkSQLiteDatabase": "androidx/sqlite/db/framework/FrameworkSQLiteDatabase",
+ "android/arch/persistence/db/framework/FrameworkSQLiteProgram": "androidx/sqlite/db/framework/FrameworkSQLiteProgram",
+ "android/arch/persistence/db/framework/FrameworkSQLiteStatement": "androidx/sqlite/db/framework/FrameworkSQLiteStatement",
+ "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper": "androidx/sqlite/db/framework/FrameworkSQLiteOpenHelper",
+ "android/support/v7/widget/GridLayout": "androidx/gridlayout/widget/GridLayout",
+ "android/support/v7/gridlayout/R": "androidx/gridlayout/R",
"android/arch/persistence/db/SupportSQLiteQueryBuilder": "androidx/sqlite/db/SupportSQLiteQueryBuilder",
- "android/support/design/animation/R": "android/support/design/animation/R",
- "android/arch/paging/PageResult": "androidx/paging/PageResult",
- "android/arch/paging/ListDataSource": "androidx/paging/ListDataSource",
- "android/arch/paging/WrapperItemKeyedDataSource": "androidx/paging/WrapperItemKeyedDataSource",
- "android/arch/paging/PageKeyedDataSource": "androidx/paging/PageKeyedDataSource",
- "android/arch/paging/ContiguousDataSource": "androidx/paging/ContiguousDataSource",
- "android/arch/paging/WrapperPageKeyedDataSource": "androidx/paging/WrapperPageKeyedDataSource",
- "android/arch/paging/ItemKeyedDataSource": "androidx/paging/ItemKeyedDataSource",
- "android/arch/paging/TiledPagedList": "androidx/paging/TiledPagedList",
- "android/arch/paging/TiledDataSource": "androidx/paging/TiledDataSource",
- "android/arch/paging/WrapperPositionalDataSource": "androidx/paging/WrapperPositionalDataSource",
- "android/arch/paging/ContiguousPagedList": "androidx/paging/ContiguousPagedList",
- "android/arch/paging/SnapshotPagedList": "androidx/paging/SnapshotPagedList",
- "android/support/v4/view/AsyncLayoutInflater": "androidx/asynclayoutinflater/view/AsyncLayoutInflater",
- "android/arch/persistence/room/ForeignKey": "androidx/room/ForeignKey",
- "android/arch/persistence/room/RoomWarnings": "androidx/room/RoomWarnings",
- "android/arch/persistence/room/Index": "androidx/room/Index",
- "android/arch/persistence/room/OnConflictStrategy": "androidx/room/OnConflictStrategy",
- "android/support/design/circularreveal/CircularRevealGridLayout": "android/support/design/circularreveal/CircularRevealGridLayout",
- "android/support/design/circularreveal/CircularRevealLinearLayout": "android/support/design/circularreveal/CircularRevealLinearLayout",
- "android/support/design/circularreveal/CircularRevealRelativeLayout": "android/support/design/circularreveal/CircularRevealRelativeLayout"
+ "android/support/v13/app/ActivityCompat": "androidx/legacy/app/ActivityCompat",
+ "android/support/v13/app/FragmentCompat": "androidx/legacy/app/FragmentCompat",
+ "android/support/v13/app/FragmentPagerAdapter": "androidx/legacy/app/FragmentPagerAdapter",
+ "android/support/v13/app/FragmentStatePagerAdapter": "androidx/legacy/app/FragmentStatePagerAdapter",
+ "android/support/v13/app/FragmentTabHost": "androidx/legacy/app/FragmentTabHost",
+ "android/support/v13/view/ViewCompat": "androidx/legacy/view/ViewCompat",
+ "android/support/annotation/BinderThread": "androidx/annotation/BinderThread",
+ "android/support/annotation/ColorLong": "androidx/annotation/ColorLong",
+ "android/support/annotation/HalfFloat": "androidx/annotation/HalfFloat",
+ "android/support/annotation/IntDef": "androidx/annotation/IntDef",
+ "android/support/annotation/InterpolatorRes": "androidx/annotation/InterpolatorRes",
+ "android/support/annotation/LongDef": "androidx/annotation/LongDef",
+ "android/support/annotation/NavigationRes": "androidx/annotation/NavigationRes",
+ "android/support/annotation/PluralsRes": "androidx/annotation/PluralsRes",
+ "android/support/annotation/RawRes": "androidx/annotation/RawRes",
+ "android/support/annotation/StringDef": "androidx/annotation/StringDef",
+ "android/support/annotation/TransitionRes": "androidx/annotation/TransitionRes",
+ "android/support/text/emoji/widget/EmojiAppCompatButton": "androidx/emoji/widget/EmojiAppCompatButton",
+ "android/support/text/emoji/widget/EmojiAppCompatEditText": "androidx/emoji/widget/EmojiAppCompatEditText",
+ "android/support/text/emoji/widget/EmojiAppCompatTextView": "androidx/emoji/widget/EmojiAppCompatTextView",
+ "android/support/graphics/drawable/Animatable2Compat": "androidx/vectordrawable/graphics/drawable/Animatable2Compat",
+ "android/support/graphics/drawable/AnimatorInflaterCompat": "androidx/vectordrawable/graphics/drawable/AnimatorInflaterCompat",
+ "android/support/graphics/drawable/AnimationUtilsCompat": "androidx/vectordrawable/graphics/drawable/AnimationUtilsCompat",
+ "android/support/graphics/drawable/PathInterpolatorCompat": "androidx/vectordrawable/graphics/drawable/PathInterpolatorCompat",
+ "android/support/graphics/drawable/ArgbEvaluator": "androidx/vectordrawable/graphics/drawable/ArgbEvaluator"
}
},
"proGuardMap": {
diff --git a/jetifier/jetifier/processor/src/main/kotlin/com/android/tools/build/jetifier/processor/transform/bytecode/CoreRemapperImpl.kt b/jetifier/jetifier/processor/src/main/kotlin/com/android/tools/build/jetifier/processor/transform/bytecode/CoreRemapperImpl.kt
index aa769dd..37a22da 100644
--- a/jetifier/jetifier/processor/src/main/kotlin/com/android/tools/build/jetifier/processor/transform/bytecode/CoreRemapperImpl.kt
+++ b/jetifier/jetifier/processor/src/main/kotlin/com/android/tools/build/jetifier/processor/transform/bytecode/CoreRemapperImpl.kt
@@ -68,11 +68,11 @@
return value
}
- val result = context.config.typesMap.mapType(type)
- if (result != null) {
- changesDone = changesDone || result != type
- Log.i(TAG, "Map string: '%s' -> '%s'", type, result)
- return result.toDotNotation()
+ val mappedType = context.config.typesMap.mapType(type)
+ if (mappedType != null) {
+ changesDone = changesDone || mappedType != type
+ Log.i(TAG, "Map string: '%s' -> '%s'", type, mappedType)
+ return mappedType.toDotNotation()
}
// We might be working with an internal type or field reference, e.g.
@@ -88,10 +88,10 @@
// Try rewrite rules
if (context.useFallbackIfTypeIsMissing) {
- val result = context.config.rulesMap.rewriteType(type)
- if (result != null) {
- Log.i(TAG, "Map string: '%s' -> '%s' via fallback", value, result)
- return result.toDotNotation()
+ val rewrittenType = context.config.rulesMap.rewriteType(type)
+ if (rewrittenType != null) {
+ Log.i(TAG, "Map string: '%s' -> '%s' via fallback", value, rewrittenType)
+ return rewrittenType.toDotNotation()
}
}
@@ -119,4 +119,4 @@
return path
}
-}
\ No newline at end of file
+}
diff --git a/leanback-preference/build.gradle b/leanback-preference/build.gradle
index a6e0d27..4f49bef 100644
--- a/leanback-preference/build.gradle
+++ b/leanback-preference/build.gradle
@@ -30,4 +30,5 @@
inceptionYear = "2015"
description = "Android Support Leanback Preference v17"
minSdkVersion = 17
+ failOnDeprecationWarnings = false
}
\ No newline at end of file
diff --git a/leanback/build.gradle b/leanback/build.gradle
index 56b7fc5..a1e468b 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -37,4 +37,6 @@
inceptionYear = "2014"
description = "Android Support Leanback v17"
minSdkVersion = 17
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/legacy/v13/build.gradle b/legacy/v13/build.gradle
index d8ef8f7..c881632 100644
--- a/legacy/v13/build.gradle
+++ b/legacy/v13/build.gradle
@@ -16,4 +16,5 @@
mavenGroup = LibraryGroups.LEGACY
inceptionYear = "2011"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnDeprecationWarnings = false
}
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index a2be25d..14a974c 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -55,4 +55,5 @@
inceptionYear = "2017"
description = "Android Lifecycle Extensions"
url = SupportLibraryExtension.ARCHITECTURE_URL
+ failOnDeprecationWarnings = false
}
diff --git a/lifecycle/livedata-core/build.gradle b/lifecycle/livedata-core/build.gradle
index 76f6c83..e9e1cfd 100644
--- a/lifecycle/livedata-core/build.gradle
+++ b/lifecycle/livedata-core/build.gradle
@@ -42,4 +42,5 @@
inceptionYear = "2017"
description = "Android Lifecycle LiveData Core"
url = SupportLibraryExtension.ARCHITECTURE_URL
+ failOnUncheckedWarnings = false
}
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index baa2b32..40b250c 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -34,4 +34,5 @@
inceptionYear '2017'
description "Android Lifecycle Runtime"
url SupportLibraryExtension.ARCHITECTURE_URL
+ failOnDeprecationWarnings = false
}
\ No newline at end of file
diff --git a/lifecycle/viewmodel/build.gradle b/lifecycle/viewmodel/build.gradle
index 1494733..cc71b39 100644
--- a/lifecycle/viewmodel/build.gradle
+++ b/lifecycle/viewmodel/build.gradle
@@ -44,4 +44,5 @@
inceptionYear = "2017"
description = "Android Lifecycle ViewModel"
url = SupportLibraryExtension.ARCHITECTURE_URL
+ failOnUncheckedWarnings = false
}
\ No newline at end of file
diff --git a/loader/build.gradle b/loader/build.gradle
index 8c99ea5..9a34ff2 100644
--- a/loader/build.gradle
+++ b/loader/build.gradle
@@ -25,4 +25,5 @@
mavenGroup = LibraryGroups.LOADER
inceptionYear = "2011"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnUncheckedWarnings = false
}
diff --git a/media-widget/api/current.txt b/media-widget/api/current.txt
new file mode 100644
index 0000000..d531c3f
--- /dev/null
+++ b/media-widget/api/current.txt
@@ -0,0 +1,36 @@
+package androidx.media.widget {
+
+ public class MediaControlView2 extends android.view.ViewGroup {
+ ctor public MediaControlView2(android.content.Context);
+ ctor public MediaControlView2(android.content.Context, android.util.AttributeSet);
+ ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int);
+ ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int, int);
+ method public void onMeasure(int, int);
+ method public void requestPlayButtonFocus();
+ }
+
+ public class VideoView2 extends android.view.ViewGroup {
+ ctor public VideoView2(android.content.Context);
+ ctor public VideoView2(android.content.Context, android.util.AttributeSet);
+ ctor public VideoView2(android.content.Context, android.util.AttributeSet, int);
+ ctor public VideoView2(android.content.Context, android.util.AttributeSet, int, int);
+ method public androidx.media.widget.MediaControlView2 getMediaControlView2();
+ method public float getSpeed();
+ method public int getViewType();
+ method public boolean isSubtitleEnabled();
+ method public void onAttachedToWindow();
+ method public void onDetachedFromWindow();
+ method public void onMeasure(int, int);
+ method public void setAudioAttributes(android.media.AudioAttributes);
+ method public void setAudioFocusRequest(int);
+ method public void setMediaControlView2(androidx.media.widget.MediaControlView2, long);
+ method public void setSpeed(float);
+ method public void setSubtitleEnabled(boolean);
+ method public void setVideoUri(android.net.Uri, java.util.Map<java.lang.String, java.lang.String>);
+ method public void setViewType(int);
+ field public static final int VIEW_TYPE_SURFACEVIEW = 0; // 0x0
+ field public static final int VIEW_TYPE_TEXTUREVIEW = 1; // 0x1
+ }
+
+}
+
diff --git a/media-widget/build.gradle b/media-widget/build.gradle
index de3f9d9..e6ff65d 100644
--- a/media-widget/build.gradle
+++ b/media-widget/build.gradle
@@ -37,10 +37,13 @@
}
supportLibrary {
- name = "Android Media Support Library"
+ name = "Android Support Media Widget"
publish = true
mavenVersion = LibraryVersions.SUPPORT_LIBRARY
mavenGroup = LibraryGroups.MEDIA
inceptionYear = "2011"
- description = "Android Media Support Library"
+ description = "Android Support Media Widget"
+ minSdkVersion = 19
+ failOnDeprecationWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/media-widget/src/main/java/androidx/media/widget/BaseLayout.java b/media-widget/src/main/java/androidx/media/widget/BaseLayout.java
index 0b6988a..982513a 100644
--- a/media-widget/src/main/java/androidx/media/widget/BaseLayout.java
+++ b/media-widget/src/main/java/androidx/media/widget/BaseLayout.java
@@ -39,7 +39,7 @@
}
BaseLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
+ super(context, attrs);
}
BaseLayout(@NonNull Context context, @Nullable AttributeSet attrs,
diff --git a/media-widget/src/main/java/androidx/media/widget/MediaControlView2.java b/media-widget/src/main/java/androidx/media/widget/MediaControlView2.java
index 89fa946..ded03cd 100644
--- a/media-widget/src/main/java/androidx/media/widget/MediaControlView2.java
+++ b/media-widget/src/main/java/androidx/media/widget/MediaControlView2.java
@@ -27,6 +27,7 @@
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -60,41 +61,34 @@
import java.util.List;
import java.util.Locale;
-// import androidx.mediarouter.app.MediaRouteButton;
-// import androidx.mediarouter.media.MediaRouter;
-// import androidx.mediarouter.media.MediaRouteSelector;
-
/**
- * @hide
- * A View that contains the controls for MediaPlayer2.
- * It provides a wide range of UI including buttons such as "Play/Pause", "Rewind", "Fast Forward",
- * "Subtitle", "Full Screen", and it is also possible to add multiple custom buttons.
+ * A View that contains the controls for {@link android.media.MediaPlayer}.
+ * It provides a wide range of buttons that serve the following functions: play/pause,
+ * rewind/fast-forward, skip to next/previous, select subtitle track, enter/exit full screen mode,
+ * adjust video quality, select audio track, mute/unmute, and adjust playback speed.
*
* <p>
* <em> MediaControlView2 can be initialized in two different ways: </em>
- * 1) When VideoView2 is initialized, it automatically initializes a MediaControlView2 instance and
- * adds it to the view.
- * 2) Initialize MediaControlView2 programmatically and add it to a ViewGroup instance.
+ * 1) When initializing {@link VideoView2} a default MediaControlView2 is created.
+ * 2) Initialize MediaControlView2 programmatically and add it to a {@link ViewGroup} instance.
*
* In the first option, VideoView2 automatically connects MediaControlView2 to MediaController,
- * which is necessary to communicate with MediaSession2. In the second option, however, the
- * developer needs to manually retrieve a MediaController instance and set it to MediaControlView2
- * by calling setController(MediaController controller).
+ * which is necessary to communicate with MediaSession. In the second option, however, the
+ * developer needs to manually retrieve a MediaController instance from MediaSession and set it to
+ * MediaControlView2.
*
* <p>
* There is no separate method that handles the show/hide behavior for MediaControlView2. Instead,
- * one can directly change the visibility of this view by calling View.setVisibility(int). The
- * values supported are View.VISIBLE and View.GONE.
- * In addition, the following customization is supported:
- * Set focus to the play/pause button by calling requestPlayButtonFocus().
+ * one can directly change the visibility of this view by calling {@link View#setVisibility(int)}.
+ * The values supported are View.VISIBLE and View.GONE.
*
* <p>
- * It is also possible to add custom buttons with custom icons and actions inside MediaControlView2.
- * Those buttons will be shown when the overflow button is clicked.
- * See VideoView2#setCustomActions for more details on how to add.
+ * In addition, the following customizations are supported:
+ * 1) Set focus to the play/pause button by calling requestPlayButtonFocus().
+ * 2) Set full screen mode
+ *
*/
@RequiresApi(21) // TODO correct minSdk API use incompatibilities and remove before release.
-@RestrictTo(LIBRARY_GROUP)
public class MediaControlView2 extends BaseLayout {
/**
* @hide
@@ -185,10 +179,6 @@
private static final String TAG = "MediaControlView2";
- static final String ARGUMENT_KEY_FULLSCREEN = "fullScreen";
-
- // TODO: Make these constants public api to support custom video view.
- // TODO: Combine these constants into one regarding TrackInfo.
static final String KEY_VIDEO_TRACK_COUNT = "VideoTrackCount";
static final String KEY_AUDIO_TRACK_COUNT = "AudioTrackCount";
static final String KEY_SUBTITLE_TRACK_COUNT = "SubtitleTrackCount";
@@ -196,8 +186,6 @@
static final String KEY_SELECTED_AUDIO_INDEX = "SelectedAudioIndex";
static final String KEY_SELECTED_SUBTITLE_INDEX = "SelectedSubtitleIndex";
static final String EVENT_UPDATE_TRACK_STATUS = "UpdateTrackStatus";
-
- // TODO: Remove this once integrating with MediaSession2 & MediaMetadata2
static final String KEY_STATE_IS_ADVERTISEMENT = "MediaTypeAdvertisement";
static final String EVENT_UPDATE_MEDIA_TYPE_STATUS = "UpdateMediaTypeStatus";
@@ -205,8 +193,6 @@
static final String COMMAND_SHOW_SUBTITLE = "showSubtitle";
// String for sending command to hide subtitle to MediaSession.
static final String COMMAND_HIDE_SUBTITLE = "hideSubtitle";
- // TODO: remove once the implementation is revised
- public static final String COMMAND_SET_FULLSCREEN = "setFullscreen";
// String for sending command to select audio track to MediaSession.
static final String COMMAND_SELECT_AUDIO_TRACK = "SelectTrack";
// String for sending command to set playback speed to MediaSession.
@@ -230,7 +216,6 @@
private static final int SIZE_TYPE_EMBEDDED = 0;
private static final int SIZE_TYPE_FULL = 1;
- // TODO: add support for Minimal size type.
private static final int SIZE_TYPE_MINIMAL = 2;
private static final int MAX_PROGRESS = 1000;
@@ -246,6 +231,7 @@
private MediaControllerCompat.TransportControls mControls;
private PlaybackStateCompat mPlaybackState;
private MediaMetadataCompat mMetadata;
+ private OnFullScreenRequestListener mFullScreenRequestListener;
private int mDuration;
private int mPrevState;
private int mPrevWidth;
@@ -284,9 +270,6 @@
private TextView mTitleView;
private View mAdExternalLink;
private ImageButton mBackButton;
- // TODO (b/77158231) revive
- // private MediaRouteButton mRouteButton;
- // private MediaRouteSelector mRouteSelector;
// Relating to Center View
private ViewGroup mCenterView;
@@ -354,20 +337,18 @@
public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
+ super(context, attrs, defStyleAttr);
+ initialize(context);
}
public MediaControlView2(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
-// super((instance, superProvider, privateProvider) ->
-// ApiLoader.getProvider().createMediaControlView2(
-// (MediaControlView2) instance, superProvider, privateProvider,
-// attrs, defStyleAttr, defStyleRes),
-// context, attrs, defStyleAttr, defStyleRes);
-// mProvider.initialize(attrs, defStyleAttr, defStyleRes);
super(context, attrs, defStyleAttr, defStyleRes);
+ initialize(context);
+ }
- mResources = getContext().getResources();
+ void initialize(Context context) {
+ mResources = context.getResources();
// Inflate MediaControlView2 from XML
mRoot = makeControllerView();
addView(mRoot);
@@ -375,27 +356,33 @@
/**
* Sets MediaSession2 token to control corresponding MediaSession2.
+ * @hide
*/
+ @RestrictTo(LIBRARY_GROUP)
public void setMediaSessionToken(SessionToken2 token) {
- //mProvider.setMediaSessionToken_impl(token);
}
/**
* Registers a callback to be invoked when the fullscreen mode should be changed.
* @param l The callback that will be run
+ * @hide TODO unhide
*/
- public void setOnFullScreenListener(OnFullScreenListener l) {
- //mProvider.setOnFullScreenListener_impl(l);
+ @RestrictTo(LIBRARY_GROUP)
+ public void setFullScreenRequestListener(OnFullScreenRequestListener l) {
+ mFullScreenRequestListener = l;
}
/**
+ * Sets MediaController instance to MediaControlView2, which makes it possible to send and
+ * receive data between MediaControlView2 and VideoView2. This method does not need to be called
+ * when MediaControlView2 is initialized with VideoView2.
* @hide TODO: remove once the implementation is revised
*/
@RestrictTo(LIBRARY_GROUP)
public void setController(MediaControllerCompat controller) {
mController = controller;
if (controller != null) {
- mControls = controller.getTransportControls();
+ mControls = mController.getTransportControls();
// Set mMetadata and mPlaybackState to existing MediaSession variables since they may
// be called before the callback is called
mPlaybackState = mController.getPlaybackState();
@@ -429,8 +416,6 @@
*/
@RestrictTo(LIBRARY_GROUP)
public void setButtonVisibility(@Button int button, /*@Visibility*/ int visibility) {
- // TODO: add member variables for Fast-Forward/Prvious/Rewind buttons to save visibility in
- // order to prevent being overriden inside updateLayout().
switch (button) {
case MediaControlView2.BUTTON_PLAY_PAUSE:
if (mPlayPauseButton != null && canPause()) {
@@ -499,12 +484,14 @@
/**
* Interface definition of a callback to be invoked to inform the fullscreen mode is changed.
* Application should handle the fullscreen mode accordingly.
+ * @hide TODO unhide
*/
- public interface OnFullScreenListener {
+ @RestrictTo(LIBRARY_GROUP)
+ public interface OnFullScreenRequestListener {
/**
* Called to indicate a fullscreen mode change.
*/
- void onFullScreen(View view, boolean fullScreen);
+ void onFullScreenRequest(View view, boolean fullScreen);
}
@Override
@@ -517,7 +504,6 @@
return false;
}
- // TODO: Should this function be removed?
@Override
public boolean onTrackballEvent(MotionEvent ev) {
return false;
@@ -551,7 +537,6 @@
R.dimen.mcv2_embedded_icon_size);
int marginSize = mResources.getDimensionPixelSize(R.dimen.mcv2_icon_margin);
- // TODO: add support for Advertisement Mode.
if (mMediaType == MEDIA_TYPE_DEFAULT) {
// Max number of icons inside BottomBarRightView for Music mode is 4.
int maxIconCount = 4;
@@ -581,7 +566,6 @@
mPrevWidth = currWidth;
mPrevHeight = currHeight;
}
- // TODO: move this to a different location.
// Update title bar parameters in order to avoid overlap between title view and the right
// side of the title bar.
updateTitleBarLayout();
@@ -591,7 +575,6 @@
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
- // TODO: Merge the below code with disableUnsupportedButtons().
if (mPlayPauseButton != null) {
mPlayPauseButton.setEnabled(enabled);
}
@@ -626,20 +609,6 @@
}
}
- // TODO (b/77158231) revive once androidx.mediarouter.* packagaes are available.
- /*
- void setRouteSelector(MediaRouteSelector selector) {
- mRouteSelector = selector;
- if (mRouteSelector != null && !mRouteSelector.isEmpty()) {
- mRouteButton.setRouteSelector(selector, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
- mRouteButton.setVisibility(View.VISIBLE);
- } else {
- mRouteButton.setRouteSelector(MediaRouteSelector.EMPTY);
- mRouteButton.setVisibility(View.GONE);
- }
- }
- */
-
///////////////////////////////////////////////////
// Protected or private methods
///////////////////////////////////////////////////
@@ -698,14 +667,12 @@
*
* @return The controller view.
*/
- // TODO: This was "protected". Determine if it should be protected in MCV2.
private ViewGroup makeControllerView() {
ViewGroup root = (ViewGroup) inflateLayout(getContext(), R.layout.media_controller);
initControllerView(root);
return root;
}
- // TODO(b/76444971) make sure this is compatible with ApiHelper's one in updatable.
private View inflateLayout(Context context, int resId) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -723,9 +690,6 @@
mBackButton.setOnClickListener(mBackListener);
mBackButton.setVisibility(View.GONE);
}
- // TODO (b/77158231) revive
- // mRouteButton = v.findViewById(R.id.cast);
-
// Relating to Center View
mCenterView = v.findViewById(R.id.center_view);
mTransportControls = inflateTransportControls(R.layout.embedded_transport_controls);
@@ -778,7 +742,6 @@
mFullScreenButton = v.findViewById(R.id.fullscreen);
if (mFullScreenButton != null) {
mFullScreenButton.setOnClickListener(mFullScreenListener);
- // TODO: Show Fullscreen button when only it is possible.
}
mOverflowButtonRight = v.findViewById(R.id.overflow_right);
if (mOverflowButtonRight != null) {
@@ -840,13 +803,6 @@
if (mFfwdButton != null && !canSeekForward()) {
mFfwdButton.setEnabled(false);
}
- // TODO What we really should do is add a canSeek to the MediaPlayerControl interface;
- // this scheme can break the case when applications want to allow seek through the
- // progress bar but disable forward/backward buttons.
- //
- // However, currently the flags SEEK_BACKWARD_AVAILABLE, SEEK_FORWARD_AVAILABLE,
- // and SEEK_AVAILABLE are all (un)set together; as such the aforementioned issue
- // shouldn't arise in existing applications.
if (mProgress != null && !canSeekBackward() && !canSeekForward()) {
mProgress.setEnabled(false);
}
@@ -1078,7 +1034,11 @@
private final OnClickListener mBackListener = new OnClickListener() {
@Override
public void onClick(View v) {
- // TODO: implement
+ View parent = (View) getParent();
+ if (parent != null) {
+ parent.onKeyDown(KeyEvent.KEYCODE_BACK,
+ new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
+ }
}
};
@@ -1105,8 +1065,11 @@
private final OnClickListener mFullScreenListener = new OnClickListener() {
@Override
public void onClick(View v) {
+ if (mFullScreenRequestListener == null) {
+ return;
+ }
+
final boolean isEnteringFullScreen = !mIsFullScreen;
- // TODO: Re-arrange the button layouts according to the UX.
if (isEnteringFullScreen) {
mFullScreenButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_fullscreen_exit, null));
@@ -1114,11 +1077,9 @@
mFullScreenButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_fullscreen, null));
}
- Bundle args = new Bundle();
- args.putBoolean(ARGUMENT_KEY_FULLSCREEN, isEnteringFullScreen);
- mController.sendCommand(COMMAND_SET_FULLSCREEN, args, null);
-
mIsFullScreen = isEnteringFullScreen;
+ mFullScreenRequestListener.onFullScreenRequest(MediaControlView2.this,
+ mIsFullScreen);
}
};
@@ -1183,7 +1144,6 @@
mSubSettingsAdapter.setCheckPosition(mSelectedSpeedIndex);
mSettingsMode = SETTINGS_MODE_PLAYBACK_SPEED;
} else if (position == SETTINGS_MODE_HELP) {
- // TODO: implement this.
mSettingsWindow.dismiss();
return;
}
@@ -1214,7 +1174,6 @@
mSettingsWindow.dismiss();
break;
case SETTINGS_MODE_HELP:
- // TODO: implement this.
break;
case SETTINGS_MODE_SUBTITLE_TRACK:
if (position != mSelectedSubtitleTrackIndex) {
@@ -1240,7 +1199,6 @@
mSettingsWindow.dismiss();
break;
case SETTINGS_MODE_VIDEO_QUALITY:
- // TODO: add support for video quality
mSelectedVideoQualityIndex = position;
mSettingsWindow.dismiss();
break;
@@ -1361,10 +1319,6 @@
int embeddedWidth = mTimeView.getWidth() + embeddedBottomBarRightWidthMax;
int screenMaxLength = Math.max(screenWidth, screenHeight);
- if (fullWidth > screenMaxLength) {
- // TODO: screen may be smaller than the length needed for Full size.
- }
-
boolean isFullSize = (mMediaType == MEDIA_TYPE_DEFAULT) ? (currWidth == screenMaxLength) :
(currWidth == screenWidth && currHeight == screenHeight);
@@ -1523,7 +1477,6 @@
mRewButton.setVisibility(View.GONE);
}
}
- // TODO: Add support for Next and Previous buttons
mNextButton = v.findViewById(R.id.next);
if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener);
@@ -1598,7 +1551,6 @@
mSettingsWindowMargin - totalHeight, Gravity.BOTTOM | Gravity.RIGHT);
}
- @RequiresApi(26) // TODO correct minSdk API use incompatibilities and remove before release.
private class MediaControllerCallback extends MediaControllerCompat.Callback {
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {
@@ -1670,16 +1622,12 @@
for (final PlaybackStateCompat.CustomAction action : customActions) {
ImageButton button = new ImageButton(getContext(),
null /* AttributeSet */, 0 /* Style */);
- // TODO: Apply R.style.BottomBarButton to this button using library context.
// Refer Constructor with argument (int defStyleRes) of View.java
button.setImageResource(action.getIcon());
- button.setTooltipText(action.getName());
final String actionString = action.getAction().toString();
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- // TODO: Currently, we are just sending extras that came from session.
- // Is it the right behavior?
mControls.sendCustomAction(actionString, action.getExtras());
setVisibility(View.VISIBLE);
}
@@ -1708,7 +1656,6 @@
mAudioTrackCount = extras.getInt(KEY_AUDIO_TRACK_COUNT);
mAudioTrackList = new ArrayList<String>();
if (mAudioTrackCount > 0) {
- // TODO: add more text about track info.
for (int i = 0; i < mAudioTrackCount; i++) {
String track = mResources.getString(
R.string.MediaControlView2_audio_track_number_text, i + 1);
@@ -1787,14 +1734,12 @@
@Override
public long getItemId(int position) {
// Auto-generated method stub--does not have any purpose here
- // TODO: implement this.
return 0;
}
@Override
public Object getItem(int position) {
// Auto-generated method stub--does not have any purpose here
- // TODO: implement this.
return null;
}
@@ -1838,7 +1783,6 @@
}
}
- // TODO: extend this class from SettingsAdapter
private class SubSettingsAdapter extends BaseAdapter {
private List<String> mTexts;
private int mCheckPosition;
@@ -1865,14 +1809,12 @@
@Override
public long getItemId(int position) {
// Auto-generated method stub--does not have any purpose here
- // TODO: implement this.
return 0;
}
@Override
public Object getItem(int position) {
// Auto-generated method stub--does not have any purpose here
- // TODO: implement this.
return null;
}
diff --git a/media-widget/src/main/java/androidx/media/widget/SubtitleView.java b/media-widget/src/main/java/androidx/media/widget/SubtitleView.java
new file mode 100644
index 0000000..1faff2f
--- /dev/null
+++ b/media-widget/src/main/java/androidx/media/widget/SubtitleView.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.os.Looper;
+import android.util.AttributeSet;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.media.subtitle.SubtitleController.Anchor;
+import androidx.media.subtitle.SubtitleTrack.RenderingWidget;
+
+@RequiresApi(21)
+class SubtitleView extends BaseLayout implements Anchor {
+ private static final String TAG = "SubtitleView";
+
+ private RenderingWidget mSubtitleWidget;
+ private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
+
+ SubtitleView(Context context) {
+ this(context, null);
+ }
+
+ SubtitleView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ SubtitleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ SubtitleView(
+ Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public void setSubtitleWidget(RenderingWidget subtitleWidget) {
+ if (mSubtitleWidget == subtitleWidget) {
+ return;
+ }
+
+ final boolean attachedToWindow = isAttachedToWindow();
+ if (mSubtitleWidget != null) {
+ if (attachedToWindow) {
+ mSubtitleWidget.onDetachedFromWindow();
+ }
+
+ mSubtitleWidget.setOnChangedListener(null);
+ }
+ mSubtitleWidget = subtitleWidget;
+
+ if (subtitleWidget != null) {
+ if (mSubtitlesChangedListener == null) {
+ mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() {
+ @Override
+ public void onChanged(RenderingWidget renderingWidget) {
+ invalidate();
+ }
+ };
+ }
+
+ setWillNotDraw(false);
+ subtitleWidget.setOnChangedListener(mSubtitlesChangedListener);
+
+ if (attachedToWindow) {
+ subtitleWidget.onAttachedToWindow();
+ requestLayout();
+ }
+ } else {
+ setWillNotDraw(true);
+ }
+
+ invalidate();
+ }
+
+ @Override
+ public Looper getSubtitleLooper() {
+ return Looper.getMainLooper();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mSubtitleWidget != null) {
+ mSubtitleWidget.onAttachedToWindow();
+ }
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mSubtitleWidget != null) {
+ mSubtitleWidget.onDetachedFromWindow();
+ }
+ }
+
+ @Override
+ public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ if (mSubtitleWidget != null) {
+ final int width = getWidth() - getPaddingLeft() - getPaddingRight();
+ final int height = getHeight() - getPaddingTop() - getPaddingBottom();
+
+ mSubtitleWidget.setSize(width, height);
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+
+ if (mSubtitleWidget != null) {
+ final int saveCount = canvas.save();
+ canvas.translate(getPaddingLeft(), getPaddingTop());
+ mSubtitleWidget.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ }
+ }
+
+ @Override
+ public CharSequence getAccessibilityClassName() {
+ return SubtitleView.class.getName();
+ }
+}
diff --git a/media-widget/src/main/java/androidx/media/widget/VideoSurfaceView.java b/media-widget/src/main/java/androidx/media/widget/VideoSurfaceView.java
index d417bd2..0af3044 100644
--- a/media-widget/src/main/java/androidx/media/widget/VideoSurfaceView.java
+++ b/media-widget/src/main/java/androidx/media/widget/VideoSurfaceView.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.graphics.Rect;
import android.media.MediaPlayer;
-import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -30,7 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
-@RequiresApi(21)
+@RequiresApi(28)
class VideoSurfaceView extends SurfaceView implements VideoViewInterface, SurfaceHolder.Callback {
private static final String TAG = "VideoSurfaceView";
private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
@@ -41,24 +40,8 @@
private boolean mIsTakingOverOldView;
private VideoViewInterface mOldView;
-
VideoSurfaceView(Context context) {
- this(context, null);
- }
-
- VideoSurfaceView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- VideoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- getHolder().addCallback(this);
- }
-
- @RequiresApi(21)
- VideoSurfaceView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
+ super(context, null);
getHolder().addCallback(this);
}
diff --git a/media-widget/src/main/java/androidx/media/widget/VideoTextureView.java b/media-widget/src/main/java/androidx/media/widget/VideoTextureView.java
index cdc833b..3b87c7e 100644
--- a/media-widget/src/main/java/androidx/media/widget/VideoTextureView.java
+++ b/media-widget/src/main/java/androidx/media/widget/VideoTextureView.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
-import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
@@ -30,7 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
-@RequiresApi(21)
+@RequiresApi(28)
class VideoTextureView extends TextureView
implements VideoViewInterface, TextureView.SurfaceTextureListener {
private static final String TAG = "VideoTextureView";
@@ -44,20 +43,7 @@
private VideoViewInterface mOldView;
VideoTextureView(Context context) {
- this(context, null);
- }
-
- VideoTextureView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- VideoTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- VideoTextureView(
- Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
+ super(context, null);
setSurfaceTextureListener(this);
}
diff --git a/media-widget/src/main/java/androidx/media/widget/VideoView2.java b/media-widget/src/main/java/androidx/media/widget/VideoView2.java
index a8ea450..6b33304 100644
--- a/media-widget/src/main/java/androidx/media/widget/VideoView2.java
+++ b/media-widget/src/main/java/androidx/media/widget/VideoView2.java
@@ -31,7 +31,9 @@
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnSubtitleDataListener;
import android.media.PlaybackParams;
+import android.media.SubtitleData;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -63,6 +65,9 @@
import androidx.media.MediaItem2;
import androidx.media.MediaMetadata2;
import androidx.media.SessionToken2;
+import androidx.media.subtitle.ClosedCaptionRenderer;
+import androidx.media.subtitle.SubtitleController;
+import androidx.media.subtitle.SubtitleTrack;
import androidx.palette.graphics.Palette;
import java.io.IOException;
@@ -73,11 +78,9 @@
import java.util.Map;
import java.util.concurrent.Executor;
-// TODO: Replace MediaSession wtih MediaSession2 once MediaSession2 is submitted.
/**
- * @hide
- * Displays a video file. VideoView2 class is a View class which is wrapping {@link MediaPlayer}
- * so that developers can easily implement a video rendering application.
+ * Displays a video file. VideoView2 class is a ViewGroup class which is wrapping
+ * {@link MediaPlayer} so that developers can easily implement a video rendering application.
*
* <p>
* <em> Data sources that VideoView2 supports : </em>
@@ -98,20 +101,12 @@
* VideoView2 covers and inherits the most of
* VideoView's functionalities. The main differences are
* <ul>
- * <li> VideoView2 inherits FrameLayout and renders videos using SurfaceView and TextureView
+ * <li> VideoView2 inherits ViewGroup and renders videos using SurfaceView and TextureView
* selectively while VideoView inherits SurfaceView class.
* <li> VideoView2 is integrated with MediaControlView2 and a default MediaControlView2 instance is
- * attached to VideoView2 by default. If a developer does not want to use the default
- * MediaControlView2, needs to set enableControlView attribute to false. For instance,
- * <pre>
- * <VideoView2
- * android:id="@+id/video_view"
- * xmlns:widget="http://schemas.android.com/apk/com.android.media.update"
- * widget:enableControlView="false" />
- * </pre>
- * If a developer wants to attach a customed MediaControlView2, then set enableControlView attribute
- * to false and assign the customed media control widget using {@link #setMediaControlView2}.
- * <li> VideoView2 is integrated with MediaPlayer while VideoView is integrated with MediaPlayer.
+ * attached to VideoView2 by default.
+ * <li> If a developer wants to attach a customed MediaControlView2,
+ * assign the customed media control widget using {@link #setMediaControlView2}.
* <li> VideoView2 is integrated with MediaSession and so it responses with media key events.
* A VideoView2 keeps a MediaSession instance internally and connects it to a corresponding
* MediaControlView2 instance.
@@ -133,8 +128,7 @@
* and restore these on their own in {@link android.app.Activity#onSaveInstanceState} and
* {@link android.app.Activity#onRestoreInstanceState}.
*/
-@RequiresApi(21) // TODO correct minSdk API use incompatibilities and remove before release.
-@RestrictTo(LIBRARY_GROUP)
+@RequiresApi(28) // TODO correct minSdk API use incompatibilities and remove before release.
public class VideoView2 extends BaseLayout implements VideoViewInterface.SurfaceListener {
/** @hide */
@RestrictTo(LIBRARY_GROUP)
@@ -160,7 +154,7 @@
public static final int VIEW_TYPE_TEXTUREVIEW = 1;
private static final String TAG = "VideoView2";
- private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final long DEFAULT_SHOW_CONTROLLER_INTERVAL_MS = 2000;
private static final int STATE_ERROR = -1;
@@ -176,7 +170,6 @@
private static final int SIZE_TYPE_EMBEDDED = 0;
private static final int SIZE_TYPE_FULL = 1;
- // TODO: add support for Minimal size type.
private static final int SIZE_TYPE_MINIMAL = 2;
private AccessibilityManager mAccessibilityManager;
@@ -187,7 +180,6 @@
private Pair<Executor, OnCustomActionListener> mCustomActionListenerRecord;
private OnViewTypeChangedListener mViewTypeChangedListener;
- private OnFullScreenRequestListener mFullScreenRequestListener;
private VideoViewInterface mCurrentView;
private VideoTextureView mTextureView;
@@ -204,7 +196,6 @@
private Bundle mMediaTypeData;
private String mTitle;
- // TODO: move music view inside SurfaceView/TextureView or implement VideoViewInterface.
private WindowManager mManager;
private Resources mResources;
private View mMusicView;
@@ -230,102 +221,24 @@
private ArrayList<Integer> mVideoTrackIndices;
private ArrayList<Integer> mAudioTrackIndices;
- // private ArrayList<Pair<Integer, SubtitleTrack>> mSubtitleTrackIndices;
- // private SubtitleController mSubtitleController;
+ private ArrayList<Pair<Integer, SubtitleTrack>> mSubtitleTrackIndices;
+ private SubtitleController mSubtitleController;
// selected video/audio/subtitle track index as MediaPlayer returns
private int mSelectedVideoTrackIndex;
private int mSelectedAudioTrackIndex;
private int mSelectedSubtitleTrackIndex;
- // private SubtitleView mSubtitleView;
+ private SubtitleView mSubtitleView;
private boolean mSubtitleEnabled;
private float mSpeed;
- // TODO: Remove mFallbackSpeed when integration with MediaPlayer's new setPlaybackParams().
- // Refer: https://docs.google.com/document/d/1nzAfns6i2hJ3RkaUre3QMT6wsDedJ5ONLiA_OOBFFX8/edit
private float mFallbackSpeed; // keep the original speed before 'pause' is called.
private float mVolumeLevelFloat;
private int mVolumeLevel;
private long mShowControllerIntervalMs;
- // private MediaRouter mMediaRouter;
- // private MediaRouteSelector mRouteSelector;
- // private MediaRouter.RouteInfo mRoute;
- // private RoutePlayer mRoutePlayer;
-
- // TODO (b/77158231)
- /*
- private final MediaRouter.Callback mRouterCallback = new MediaRouter.Callback() {
- @Override
- public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
- if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
- // Stop local playback (if necessary)
- resetPlayer();
- mRoute = route;
- mRoutePlayer = new RoutePlayer(getContext(), route);
- mRoutePlayer.setPlayerEventCallback(new RoutePlayer.PlayerEventCallback() {
- @Override
- public void onPlayerStateChanged(MediaItemStatus itemStatus) {
- PlaybackStateCompat.Builder psBuilder = new PlaybackStateCompat.Builder();
- psBuilder.setActions(RoutePlayer.PLAYBACK_ACTIONS);
- long position = itemStatus.getContentPosition();
- switch (itemStatus.getPlaybackState()) {
- case MediaItemStatus.PLAYBACK_STATE_PENDING:
- psBuilder.setState(PlaybackStateCompat.STATE_NONE, position, 0);
- mCurrentState = STATE_IDLE;
- break;
- case MediaItemStatus.PLAYBACK_STATE_PLAYING:
- psBuilder.setState(PlaybackStateCompat.STATE_PLAYING, position, 1);
- mCurrentState = STATE_PLAYING;
- break;
- case MediaItemStatus.PLAYBACK_STATE_PAUSED:
- psBuilder.setState(PlaybackStateCompat.STATE_PAUSED, position, 0);
- mCurrentState = STATE_PAUSED;
- break;
- case MediaItemStatus.PLAYBACK_STATE_BUFFERING:
- psBuilder.setState(
- PlaybackStateCompat.STATE_BUFFERING, position, 0);
- mCurrentState = STATE_PAUSED;
- break;
- case MediaItemStatus.PLAYBACK_STATE_FINISHED:
- psBuilder.setState(PlaybackStateCompat.STATE_STOPPED, position, 0);
- mCurrentState = STATE_PLAYBACK_COMPLETED;
- break;
- }
-
- PlaybackStateCompat pbState = psBuilder.build();
- mMediaSession.setPlaybackState(pbState);
-
- MediaMetadataCompat.Builder mmBuilder = new MediaMetadataCompat.Builder();
- mmBuilder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION,
- itemStatus.getContentDuration());
- mMediaSession.setMetadata(mmBuilder.build());
- }
- });
- // Start remote playback (if necessary)
- mRoutePlayer.openVideo(mDsd);
- }
- }
-
- @Override
- public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo route, int reason) {
- if (mRoute != null && mRoutePlayer != null) {
- mRoutePlayer.release();
- mRoutePlayer = null;
- }
- if (mRoute == route) {
- mRoute = null;
- }
- if (reason != MediaRouter.UNSELECT_REASON_ROUTE_CHANGED) {
- // TODO: Resume local playback (if necessary)
- openVideo(mDsd);
- }
- }
- };
- */
-
public VideoView2(@NonNull Context context) {
this(context, null);
}
@@ -335,19 +248,22 @@
}
public VideoView2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
+ super(context, attrs, defStyleAttr);
+ initialize(context, attrs);
}
public VideoView2(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ initialize(context, attrs);
+ }
+ void initialize(Context context, AttributeSet attrs) {
mVideoWidth = 0;
mVideoHeight = 0;
mSpeed = 1.0f;
mFallbackSpeed = mSpeed;
mSelectedSubtitleTrackIndex = INVALID_TRACK_INDEX;
- // TODO: add attributes to get this value.
mShowControllerIntervalMs = DEFAULT_SHOW_CONTROLLER_INTERVAL_MS;
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
@@ -360,9 +276,8 @@
setFocusableInTouchMode(true);
requestFocus();
- // TODO: try to keep a single child at a time rather than always having both.
- mTextureView = new VideoTextureView(getContext());
- mSurfaceView = new VideoSurfaceView(getContext());
+ mTextureView = new VideoTextureView(context);
+ mSurfaceView = new VideoSurfaceView(context);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
mTextureView.setLayoutParams(params);
@@ -373,23 +288,22 @@
addView(mTextureView);
addView(mSurfaceView);
- // mSubtitleView = new SubtitleView(getContext());
- // mSubtitleView.setLayoutParams(params);
- // mSubtitleView.setBackgroundColor(0);
- // addView(mSubtitleView);
+ mSubtitleView = new SubtitleView(context);
+ mSubtitleView.setLayoutParams(params);
+ mSubtitleView.setBackgroundColor(0);
+ addView(mSubtitleView);
boolean enableControlView = (attrs == null) || attrs.getAttributeBooleanValue(
"http://schemas.android.com/apk/res/android",
"enableControlView", true);
if (enableControlView) {
- mMediaControlView = new MediaControlView2(getContext());
+ mMediaControlView = new MediaControlView2(context);
}
mSubtitleEnabled = (attrs == null) || attrs.getAttributeBooleanValue(
"http://schemas.android.com/apk/res/android",
"enableSubtitle", false);
- // TODO: Choose TextureView when SurfaceView cannot be created.
// Choose surface view by default
int viewType = (attrs == null) ? VideoView2.VIEW_TYPE_SURFACEVIEW
: attrs.getAttributeIntValue(
@@ -406,15 +320,6 @@
mSurfaceView.setVisibility(View.GONE);
mCurrentView = mTextureView;
}
-
- // TODO (b/77158231)
- /*
- MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder();
- builder.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
- builder.addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO);
- builder.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO);
- mRouteSelector = builder.build();
- */
}
/**
@@ -427,10 +332,6 @@
public void setMediaControlView2(MediaControlView2 mediaControlView, long intervalMs) {
mMediaControlView = mediaControlView;
mShowControllerIntervalMs = intervalMs;
- // TODO: Call MediaControlView2.setRouteSelector only when cast availalbe.
- // TODO (b/77158231)
- // mMediaControlView.setRouteSelector(mRouteSelector);
-
if (isAttachedToWindow()) {
attachMediaControlView();
}
@@ -529,7 +430,6 @@
* be reset to the normal speed 1.0f.
* @param speed the playback speed. It should be positive.
*/
- // TODO: Support this via MediaController2.
public void setSpeed(float speed) {
if (speed <= 0.0f) {
Log.e(TAG, "Unsupported speed (" + speed + ") is ignored.");
@@ -543,6 +443,16 @@
}
/**
+ * Returns playback speed.
+ *
+ * It returns the same value that has been set by {@link #setSpeed}, if it was available value.
+ * If {@link #setSpeed} has not been called before, then the normal speed 1.0f will be returned.
+ */
+ public float getSpeed() {
+ return mSpeed;
+ }
+
+ /**
* Sets which type of audio focus will be requested during the playback, or configures playback
* to not request audio focus. Valid values for focus requests are
* {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
@@ -585,7 +495,7 @@
*
* @param path the path of the video.
*
- * @hide TODO remove
+ * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public void setVideoPath(String path) {
@@ -597,7 +507,7 @@
*
* @param uri the URI of the video.
*
- * @hide TODO remove
+ * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public void setVideoUri(Uri uri) {
@@ -613,11 +523,8 @@
* changed with key/value pairs through the headers parameter with
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
* to disallow or allow cross domain redirection.
- *
- * @hide TODO remove
*/
- @RestrictTo(LIBRARY_GROUP)
- public void setVideoUri(Uri uri, Map<String, String> headers) {
+ public void setVideoUri(Uri uri, @Nullable Map<String, String> headers) {
mSeekWhenPrepared = 0;
openVideo(uri, headers);
}
@@ -627,9 +534,11 @@
* object to VideoView2 is {@link #setDataSource}.
* @param mediaItem the MediaItem2 to play
* @see #setDataSource
+ *
+ * @hide
*/
+ @RestrictTo(LIBRARY_GROUP)
public void setMediaItem(@NonNull MediaItem2 mediaItem) {
- //mProvider.setMediaItem_impl(mediaItem);
}
/**
@@ -640,7 +549,6 @@
*/
@RestrictTo(LIBRARY_GROUP)
public void setDataSource(@NonNull DataSourceDesc dataSource) {
- //mProvider.setDataSource_impl(dataSource);
}
/**
@@ -689,7 +597,7 @@
* buttons in {@link MediaControlView2}.
* @param executor executor to run callbacks on.
* @param listener A listener to be called when a custom button is clicked.
- * @hide TODO remove
+ * @hide
*/
@RestrictTo(LIBRARY_GROUP)
public void setCustomActions(List<PlaybackStateCompat.CustomAction> actionList,
@@ -714,16 +622,6 @@
mViewTypeChangedListener = l;
}
- /**
- * Registers a callback to be invoked when the fullscreen mode should be changed.
- * @param l The callback that will be run
- * @hide TODO remove
- */
- @RestrictTo(LIBRARY_GROUP)
- public void setFullScreenRequestListener(OnFullScreenRequestListener l) {
- mFullScreenRequestListener = l;
- }
-
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -733,12 +631,7 @@
mMediaSession.setCallback(new MediaSessionCallback());
mMediaSession.setActive(true);
mMediaController = mMediaSession.getController();
- // TODO (b/77158231)
- // mMediaRouter = MediaRouter.getInstance(getContext());
- // mMediaRouter.setMediaSession(mMediaSession);
- // mMediaRouter.addCallback(mRouteSelector, mRouterCallback);
attachMediaControlView();
- // TODO: remove this after moving MediaSession creating code inside initializing VideoView2
if (mCurrentState == STATE_PREPARED) {
extractTracks();
extractMetadata();
@@ -794,7 +687,6 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- // TODO: Test touch event handling logic thoroughly and simplify the logic.
return super.dispatchTouchEvent(ev);
}
@@ -862,19 +754,6 @@
}
/**
- * Interface definition of a callback to be invoked to inform the fullscreen mode is changed.
- * Application should handle the fullscreen mode accordingly.
- * @hide TODO remove
- */
- @RestrictTo(LIBRARY_GROUP)
- public interface OnFullScreenRequestListener {
- /**
- * Called to indicate a fullscreen mode change.
- */
- void onFullScreenRequest(View view, boolean fullScreen);
- }
-
- /**
* Interface definition of a callback to be invoked to inform that a custom action is performed.
* @hide TODO remove
*/
@@ -894,7 +773,11 @@
// Implements VideoViewInterface.SurfaceListener
///////////////////////////////////////////////////
+ /**
+ * @hide
+ */
@Override
+ @RestrictTo(LIBRARY_GROUP)
public void onSurfaceCreated(View view, int width, int height) {
if (DEBUG) {
Log.d(TAG, "onSurfaceCreated(). mCurrentState=" + mCurrentState
@@ -906,7 +789,11 @@
}
}
+ /**
+ * @hide
+ */
@Override
+ @RestrictTo(LIBRARY_GROUP)
public void onSurfaceDestroyed(View view) {
if (DEBUG) {
Log.d(TAG, "onSurfaceDestroyed(). mCurrentState=" + mCurrentState
@@ -914,16 +801,23 @@
}
}
+ /**
+ * @hide
+ */
@Override
+ @RestrictTo(LIBRARY_GROUP)
public void onSurfaceChanged(View view, int width, int height) {
- // TODO: Do we need to call requestLayout here?
if (DEBUG) {
Log.d(TAG, "onSurfaceChanged(). width/height: " + width + "/" + height
+ ", " + view.toString());
}
}
+ /**
+ * @hide
+ */
@Override
+ @RestrictTo(LIBRARY_GROUP)
public void onSurfaceTakeOverDone(VideoViewInterface view) {
if (DEBUG) {
Log.d(TAG, "onSurfaceTakeOverDone(). Now current view is: " + view);
@@ -951,8 +845,6 @@
}
private boolean isInPlaybackState() {
- // TODO (b/77158231)
- // return (mMediaPlayer != null || mRoutePlayer != null)
return (mMediaPlayer != null)
&& mCurrentState != STATE_ERROR
&& mCurrentState != STATE_IDLE
@@ -960,8 +852,6 @@
}
private boolean needToStart() {
- // TODO (b/77158231)
- // return (mMediaPlayer != null || mRoutePlayer != null)
return (mMediaPlayer != null)
&& isAudioGranted()
&& isWaitingPlayback();
@@ -989,11 +879,6 @@
case AudioManager.AUDIOFOCUS_LOSS:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
- // There is no way to distinguish pause() by transient
- // audio focus loss and by other explicit actions.
- // TODO: If we can distinguish those cases, change the code to resume when it
- // gains audio focus again for AUDIOFOCUS_LOSS_TRANSIENT and
- // AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
mAudioFocused = false;
if (isInPlaybackState() && mMediaPlayer.isPlaying()) {
mMediaController.getTransportControls().pause();
@@ -1032,8 +917,6 @@
private void openVideo(Uri uri, Map<String, String> headers) {
resetPlayer();
if (isRemotePlayback()) {
- // TODO (b/77158231)
- // mRoutePlayer.openVideo(dsd);
return;
}
@@ -1045,10 +928,9 @@
mCurrentView.assignSurfaceToMediaPlayer(mMediaPlayer);
final Context context = getContext();
- // TODO: Add timely firing logic for more accurate sync between CC and video frame
- // mSubtitleController = new SubtitleController(context);
- // mSubtitleController.registerRenderer(new ClosedCaptionRenderer(context));
- // mSubtitleController.setAnchor((SubtitleController.Anchor) mSubtitleView);
+ mSubtitleController = new SubtitleController(context);
+ mSubtitleController.registerRenderer(new ClosedCaptionRenderer(context));
+ mSubtitleController.setAnchor((SubtitleController.Anchor) mSubtitleView);
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
@@ -1061,7 +943,7 @@
mCurrentBufferPercentage = -1;
mMediaPlayer.setDataSource(getContext(), uri, headers);
mMediaPlayer.setAudioAttributes(mAudioAttributes);
- // mMediaPlayer.setOnSubtitleDataListener(mSubtitleListener);
+ mMediaPlayer.setOnSubtitleDataListener(mSubtitleListener);
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
@@ -1112,38 +994,6 @@
private void updatePlaybackState() {
if (mStateBuilder == null) {
- /*
- // Get the capabilities of the player for this stream
- mMetadata = mMediaPlayer.getMetadata(MediaPlayer.METADATA_ALL,
- MediaPlayer.BYPASS_METADATA_FILTER);
-
- // Add Play action as default
- long playbackActions = PlaybackStateCompat.ACTION_PLAY;
- if (mMetadata != null) {
- if (!mMetadata.has(Metadata.PAUSE_AVAILABLE)
- || mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)) {
- playbackActions |= PlaybackStateCompat.ACTION_PAUSE;
- }
- if (!mMetadata.has(Metadata.SEEK_BACKWARD_AVAILABLE)
- || mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)) {
- playbackActions |= PlaybackStateCompat.ACTION_REWIND;
- }
- if (!mMetadata.has(Metadata.SEEK_FORWARD_AVAILABLE)
- || mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)) {
- playbackActions |= PlaybackStateCompat.ACTION_FAST_FORWARD;
- }
- if (!mMetadata.has(Metadata.SEEK_AVAILABLE)
- || mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)) {
- playbackActions |= PlaybackStateCompat.ACTION_SEEK_TO;
- }
- } else {
- playbackActions |= (PlaybackStateCompat.ACTION_PAUSE
- | PlaybackStateCompat.ACTION_REWIND
- | PlaybackStateCompat.ACTION_FAST_FORWARD
- | PlaybackStateCompat.ACTION_SEEK_TO);
- }
- */
- // TODO determine the actionable list based the metadata info.
long playbackActions = PlaybackStateCompat.ACTION_PLAY
| PlaybackStateCompat.ACTION_PAUSE
| PlaybackStateCompat.ACTION_REWIND | PlaybackStateCompat.ACTION_FAST_FORWARD
@@ -1162,8 +1012,6 @@
if (mCurrentState != STATE_ERROR
&& mCurrentState != STATE_IDLE
&& mCurrentState != STATE_PREPARING) {
- // TODO: this should be replaced with MediaPlayer2.getBufferedPosition() once it is
- // implemented.
if (mCurrentBufferPercentage == -1) {
mStateBuilder.setBufferedPosition(-1);
} else {
@@ -1210,7 +1058,6 @@
};
private void showController() {
- // TODO: Decide what to show when the state is not in playback state
if (mMediaControlView == null || !isInPlaybackState()
|| (mIsMusicMediaType && mSizeType == SIZE_TYPE_FULL)) {
return;
@@ -1234,7 +1081,6 @@
private void applySpeed() {
if (android.os.Build.VERSION.SDK_INT < 23) {
- // TODO: MediaPlayer2 will cover this, or implement with SoundPool.
return;
}
PlaybackParams params = mMediaPlayer.getPlaybackParams().allowDefaults();
@@ -1245,11 +1091,6 @@
mFallbackSpeed = mSpeed;
} catch (IllegalArgumentException e) {
Log.e(TAG, "PlaybackParams has unsupported value: " + e);
- // TODO: should revise this part after integrating with MP2.
- // If mSpeed had an illegal value for speed rate, system will determine best
- // handling (see PlaybackParams.AUDIO_FALLBACK_MODE_DEFAULT).
- // Note: The pre-MP2 returns 0.0f when it is paused. In this case, VideoView2 will
- // use mFallbackSpeed instead.
float fallbackSpeed = mMediaPlayer.getPlaybackParams().allowDefaults().getSpeed();
if (fallbackSpeed > 0.0f) {
mFallbackSpeed = fallbackSpeed;
@@ -1272,10 +1113,8 @@
if (!isInPlaybackState()) {
return;
}
- /*
if (select) {
if (mSubtitleTrackIndices.size() > 0) {
- // TODO: make this selection dynamic
mSelectedSubtitleTrackIndex = mSubtitleTrackIndices.get(0).first;
mSubtitleController.selectTrack(mSubtitleTrackIndices.get(0).second);
mMediaPlayer.selectTrack(mSelectedSubtitleTrackIndex);
@@ -1288,31 +1127,25 @@
mSubtitleView.setVisibility(View.GONE);
}
}
- */
}
private void extractTracks() {
MediaPlayer.TrackInfo[] trackInfos = mMediaPlayer.getTrackInfo();
mVideoTrackIndices = new ArrayList<>();
mAudioTrackIndices = new ArrayList<>();
- /*
mSubtitleTrackIndices = new ArrayList<>();
mSubtitleController.reset();
- */
for (int i = 0; i < trackInfos.length; ++i) {
int trackType = trackInfos[i].getTrackType();
if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_VIDEO) {
mVideoTrackIndices.add(i);
} else if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_AUDIO) {
mAudioTrackIndices.add(i);
- /*
- } else if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
- || trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ } else if (trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
SubtitleTrack track = mSubtitleController.addTrack(trackInfos[i].getFormat());
if (track != null) {
mSubtitleTrackIndices.add(new Pair<>(i, track));
}
- */
}
}
// Select first tracks as default
@@ -1329,12 +1162,10 @@
Bundle data = new Bundle();
data.putInt(MediaControlView2.KEY_VIDEO_TRACK_COUNT, mVideoTrackIndices.size());
data.putInt(MediaControlView2.KEY_AUDIO_TRACK_COUNT, mAudioTrackIndices.size());
- /*
data.putInt(MediaControlView2.KEY_SUBTITLE_TRACK_COUNT, mSubtitleTrackIndices.size());
if (mSubtitleTrackIndices.size() > 0) {
selectOrDeselectSubtitle(mSubtitleEnabled);
}
- */
mMediaSession.sendSessionEvent(MediaControlView2.EVENT_UPDATE_TRACK_STATUS, data);
}
@@ -1369,12 +1200,10 @@
Bitmap bitmap = BitmapFactory.decodeByteArray(album, 0, album.length);
mMusicAlbumDrawable = new BitmapDrawable(bitmap);
- // TODO: replace with visualizer
Palette.Builder builder = Palette.from(bitmap);
builder.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
- // TODO: add dominant color for default album image.
mDominantColor = palette.getDominantColor(0);
if (mMusicView != null) {
mMusicView.setBackgroundColor(mDominantColor);
@@ -1448,7 +1277,6 @@
addView(mMusicView, 0);
}
- /*
OnSubtitleDataListener mSubtitleListener =
new OnSubtitleDataListener() {
@Override
@@ -1476,7 +1304,6 @@
}
}
};
- */
MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
new MediaPlayer.OnVideoSizeChangedListener() {
@@ -1508,8 +1335,6 @@
// Create and set playback state for MediaControlView2
updatePlaybackState();
- // TODO: change this to send TrackInfos to MediaControlView2
- // TODO: create MediaSession when initializing VideoView2
if (mMediaSession != null) {
extractTracks();
}
@@ -1553,20 +1378,12 @@
// Get and set duration and title values as MediaMetadata for MediaControlView2
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
- // TODO: Get title via other public APIs.
- /*
- if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
- mTitle = mMetadata.getString(Metadata.TITLE);
- }
- */
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, mTitle);
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
if (mMediaSession != null) {
mMediaSession.setMetadata(builder.build());
- // TODO: merge this code with the above code when integrating with
- // MediaSession2.
if (mNeedUpdateMediaType) {
mMediaSession.sendSessionEvent(
MediaControlView2.EVENT_UPDATE_MEDIA_TYPE_STATUS, mMediaTypeData);
@@ -1637,12 +1454,9 @@
@Override
public void onCommand(String command, Bundle args, ResultReceiver receiver) {
if (isRemotePlayback()) {
- // TODO (b/77158231)
- // mRoutePlayer.onCommand(command, args, receiver);
} else {
switch (command) {
case MediaControlView2.COMMAND_SHOW_SUBTITLE:
- /*
int subtitleIndex = args.getInt(
MediaControlView2.KEY_SELECTED_SUBTITLE_INDEX,
INVALID_TRACK_INDEX);
@@ -1653,18 +1467,10 @@
setSubtitleEnabled(true);
}
}
- */
break;
case MediaControlView2.COMMAND_HIDE_SUBTITLE:
setSubtitleEnabled(false);
break;
- case MediaControlView2.COMMAND_SET_FULLSCREEN:
- if (mFullScreenRequestListener != null) {
- mFullScreenRequestListener.onFullScreenRequest(
- VideoView2.this,
- args.getBoolean(MediaControlView2.ARGUMENT_KEY_FULLSCREEN));
- }
- break;
case MediaControlView2.COMMAND_SELECT_AUDIO_TRACK:
int audioIndex = args.getInt(MediaControlView2.KEY_SELECTED_AUDIO_INDEX,
INVALID_TRACK_INDEX);
@@ -1715,8 +1521,6 @@
if ((isInPlaybackState() && mCurrentView.hasAvailableSurface()) || mIsMusicMediaType) {
if (isRemotePlayback()) {
- // TODO (b/77158231)
- // mRoutePlayer.onPlay();
} else {
applySpeed();
mMediaPlayer.start();
@@ -1737,8 +1541,6 @@
public void onPause() {
if (isInPlaybackState()) {
if (isRemotePlayback()) {
- // TODO (b/77158231)
- // mRoutePlayer.onPause();
mCurrentState = STATE_PAUSED;
} else if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
@@ -1758,10 +1560,7 @@
public void onSeekTo(long pos) {
if (isInPlaybackState()) {
if (isRemotePlayback()) {
- // TODO (b/77158231)
- // mRoutePlayer.onSeekTo(pos);
} else {
- // TODO Refactor VideoView2 with FooImplBase and FooImplApiXX.
if (android.os.Build.VERSION.SDK_INT < 26) {
mMediaPlayer.seekTo((int) pos);
} else {
@@ -1778,8 +1577,6 @@
@Override
public void onStop() {
if (isRemotePlayback()) {
- // TODO (b/77158231)
- // mRoutePlayer.onStop();
} else {
resetPlayer();
}
diff --git a/media/src/androidTest/java/androidx/media/MediaBrowser2Test.java b/media/src/androidTest/java/androidx/media/MediaBrowser2Test.java
index 4b75986..3b7e0e3 100644
--- a/media/src/androidTest/java/androidx/media/MediaBrowser2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaBrowser2Test.java
@@ -29,9 +29,11 @@
import static org.junit.Assert.assertNotEquals;
import android.content.Context;
+import android.os.Build;
import android.os.Bundle;
import android.os.Process;
import android.os.ResultReceiver;
+import android.support.test.filters.SdkSuppress;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -65,17 +67,15 @@
* {@link MediaController2} works cleanly.
*/
// TODO(jaewan): Implement host-side test so browser and service can run in different processes.
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
@RunWith(AndroidJUnit4.class)
@SmallTest
-@Ignore
public class MediaBrowser2Test extends MediaController2Test {
private static final String TAG = "MediaBrowser2Test";
@Override
TestControllerInterface onCreateController(final @NonNull SessionToken2 token,
- @Nullable ControllerCallback callback) throws InterruptedException {
- final BrowserCallback browserCallback =
- callback != null ? (BrowserCallback) callback : new BrowserCallback() {};
+ final @Nullable ControllerCallback callback) throws InterruptedException {
final AtomicReference<TestControllerInterface> controller = new AtomicReference<>();
sHandler.postAndSync(new Runnable() {
@Override
@@ -84,7 +84,7 @@
// Looper. Otherwise, MediaBrowserCompat will post all the commands to the handler
// and commands wouldn't be run if tests codes waits on the test handler.
controller.set(new TestMediaBrowser(
- mContext, token, new TestBrowserCallback(browserCallback)));
+ mContext, token, new TestBrowserCallback(callback)));
}
});
return controller.get();
@@ -120,7 +120,9 @@
Bundle rootHints, String rootMediaId, Bundle rootExtra) {
assertTrue(TestUtils.equals(param, rootHints));
assertEquals(ROOT_ID, rootMediaId);
- assertTrue(TestUtils.equals(EXTRAS, rootExtra));
+ // Note that TestUtils#equals() cannot be used for this because
+ // MediaBrowserServiceCompat adds extra_client_version to the rootHints.
+ assertTrue(TestUtils.contains(rootExtra, EXTRAS));
latch.countDown();
}
};
@@ -316,6 +318,7 @@
assertTrue(latchForGetSearchResult.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
}
+ @Ignore
@Test
public void testSearchTakesTime() throws InterruptedException {
prepareLooper();
@@ -342,6 +345,7 @@
MockMediaLibraryService2.SEARCH_TIME_IN_MS + WAIT_TIME_MS, TimeUnit.MILLISECONDS));
}
+ @Ignore
@Test
public void testSearchEmptyResult() throws InterruptedException {
prepareLooper();
@@ -504,7 +508,7 @@
TestBrowserCallback(ControllerCallback callbackProxy) {
if (callbackProxy == null) {
- throw new IllegalArgumentException("Callback proxy shouldn't be null. Test bug");
+ callbackProxy = new BrowserCallback() {};
}
mCallbackProxy = callbackProxy;
}
@@ -690,9 +694,9 @@
private final BrowserCallback mCallback;
public TestMediaBrowser(@NonNull Context context, @NonNull SessionToken2 token,
- @NonNull ControllerCallback callback) {
- super(context, token, sHandlerExecutor, (BrowserCallback) callback);
- mCallback = (BrowserCallback) callback;
+ @NonNull BrowserCallback callback) {
+ super(context, token, sHandlerExecutor, callback);
+ mCallback = callback;
}
@Override
diff --git a/media/src/androidTest/java/androidx/media/MediaController2Test.java b/media/src/androidTest/java/androidx/media/MediaController2Test.java
index 75c9e50..d60a01e 100644
--- a/media/src/androidTest/java/androidx/media/MediaController2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaController2Test.java
@@ -49,7 +49,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -212,6 +211,7 @@
final long position = 150000;
final long bufferedPosition = 900000;
final float speed = 0.5f;
+ final long timeDiff = 102;
final MediaItem2 currentMediaItem = TestUtils.createMediaItemWithMetadata();
mPlayer.mLastPlayerState = state;
@@ -221,18 +221,12 @@
mPlayer.mPlaybackSpeed = speed;
mMockAgent.mCurrentMediaItem = currentMediaItem;
- long time1 = System.currentTimeMillis();
MediaController2 controller = createController(mSession.getToken());
- long time2 = System.currentTimeMillis();
+ controller.setTimeDiff(timeDiff);
assertEquals(state, controller.getPlayerState());
assertEquals(bufferedPosition, controller.getBufferedPosition());
assertEquals(speed, controller.getPlaybackSpeed(), 0.0f);
- long positionLowerBound = (long) (position + speed * (System.currentTimeMillis() - time2));
- long currentPosition = controller.getCurrentPosition();
- long positionUpperBound = (long) (position + speed * (System.currentTimeMillis() - time1));
- assertTrue("curPos=" + currentPosition + ", lowerBound=" + positionLowerBound
- + ", upperBound=" + positionUpperBound,
- positionLowerBound <= currentPosition && currentPosition <= positionUpperBound);
+ assertEquals(position + (long) (speed * timeDiff), controller.getCurrentPosition());
assertEquals(currentMediaItem, controller.getCurrentMediaItem());
}
@@ -420,6 +414,77 @@
}
}
+
+ @Test
+ public void testControllerCallback_onSeekCompleted() throws InterruptedException {
+ prepareLooper();
+ final long testSeekPosition = 400;
+ final long testPosition = 500;
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ControllerCallback callback = new ControllerCallback() {
+ @Override
+ public void onSeekCompleted(MediaController2 controller, long position) {
+ controller.setTimeDiff(Long.valueOf(0));
+ assertEquals(testSeekPosition, position);
+ assertEquals(testPosition, controller.getCurrentPosition());
+ latch.countDown();
+ }
+ };
+ final MediaController2 controller = createController(mSession.getToken(), true, callback);
+ mPlayer.mCurrentPosition = testPosition;
+ mPlayer.notifySeekCompleted(testSeekPosition);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testControllerCallback_onBufferingStateChanged() throws InterruptedException {
+ prepareLooper();
+ final List<MediaItem2> testPlaylist = TestUtils.createPlaylist(3);
+ final MediaItem2 testItem = testPlaylist.get(0);
+ final int testBufferingState = MediaPlayerBase.BUFFERING_STATE_BUFFERING_AND_PLAYABLE;
+ final long testBufferingPosition = 500;
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ControllerCallback callback = new ControllerCallback() {
+ @Override
+ public void onBufferingStateChanged(MediaController2 controller, MediaItem2 item,
+ int state) {
+ controller.setTimeDiff(Long.valueOf(0));
+ assertEquals(testItem, item);
+ assertEquals(testBufferingState, state);
+ assertEquals(testBufferingState, controller.getBufferingState());
+ assertEquals(testBufferingPosition, controller.getBufferedPosition());
+ latch.countDown();
+ }
+ };
+ final MediaController2 controller = createController(mSession.getToken(), true, callback);
+ mSession.setPlaylist(testPlaylist, null);
+ mPlayer.mBufferedPosition = testBufferingPosition;
+ mPlayer.notifyBufferingStateChanged(testItem.getDataSourceDesc(), testBufferingState);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testControllerCallback_onPlayerStateChanged() throws InterruptedException {
+ prepareLooper();
+ final int testPlayerState = MediaPlayerBase.PLAYER_STATE_PLAYING;
+ final long testPosition = 500;
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ControllerCallback callback = new ControllerCallback() {
+ @Override
+ public void onPlayerStateChanged(MediaController2 controller, int state) {
+ controller.setTimeDiff(Long.valueOf(0));
+ assertEquals(testPlayerState, state);
+ assertEquals(testPlayerState, controller.getPlayerState());
+ assertEquals(testPosition, controller.getCurrentPosition());
+ latch.countDown();
+ }
+ };
+ final MediaController2 controller = createController(mSession.getToken(), true, callback);
+ mPlayer.mCurrentPosition = testPosition;
+ mPlayer.notifyPlaybackState(testPlayerState);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
@Test
public void testAddPlaylistItem() throws InterruptedException {
prepareLooper();
@@ -1065,30 +1130,29 @@
};
TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
- mController = createController(TestUtils.getServiceToken(mContext, id));
+ final SessionCommand2 testCommand = new SessionCommand2("testConnectToService", null);
+ final CountDownLatch controllerLatch = new CountDownLatch(1);
+ mController = createController(TestUtils.getServiceToken(mContext, id), true,
+ new ControllerCallback() {
+ @Override
+ public void onCustomCommand(MediaController2 controller,
+ SessionCommand2 command, Bundle args, ResultReceiver receiver) {
+ if (testCommand.equals(command)) {
+ controllerLatch.countDown();
+ }
+ }
+ }
+ );
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- // Test command from controller to session service
- // TODO: Re enable when transport control works
- /*
+ // Test command from controller to session service.
mController.play();
assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertTrue(mPlayer.mPlayCalled);
- */
- // Test command from session service to controller
- // TODO(jaewan): Add equivalent tests again
- /*
- final CountDownLatch latch = new CountDownLatch(1);
- mController.registerPlayerEventCallback((state) -> {
- assertNotNull(state);
- assertEquals(PlaybackState.STATE_REWINDING, state.getState());
- latch.countDown();
- }, sHandler);
- mPlayer.notifyPlaybackState(
- TestUtils.createPlaybackState(PlaybackState.STATE_REWINDING));
- assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- */
+ // Test command from session service to controller.
+ mSession.sendCustomCommand(testCommand, null);
+ assertTrue(controllerLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
}
@Test
@@ -1097,15 +1161,11 @@
testControllerAfterSessionIsClosed(mSession.getToken().getId());
}
- // TODO(jaewan): Re-enable this test
- @Ignore
@Test
public void testControllerAfterSessionIsClosed_sessionService() throws InterruptedException {
prepareLooper();
- /*
- connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
+ testConnectToService(MockMediaSessionService2.ID);
testControllerAfterSessionIsClosed(MockMediaSessionService2.ID);
- */
}
@Test
@@ -1192,14 +1252,12 @@
testControllerAfterSessionIsClosed(id);
}
- @Ignore
@Test
public void testClose_sessionService() throws InterruptedException {
prepareLooper();
testCloseFromService(MockMediaSessionService2.ID);
}
- @Ignore
@Test
public void testClose_libraryService() throws InterruptedException {
prepareLooper();
diff --git a/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java b/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
index f565e8a..aff005d 100644
--- a/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaPlayer2Test.java
@@ -29,6 +29,7 @@
import android.media.MediaRecorder;
import android.media.MediaTimestamp;
import android.media.PlaybackParams;
+import android.media.SubtitleData;
import android.media.SyncParams;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.Visualizer;
@@ -36,6 +37,7 @@
import android.os.Build;
import android.os.Environment;
import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
@@ -54,9 +56,11 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
+import java.util.concurrent.BlockingDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -81,7 +85,7 @@
@Before
@Override
- public void setUp() throws Exception {
+ public void setUp() throws Throwable {
super.setUp();
mRecordedFilePath = new File(Environment.getExternalStorageDirectory(),
"mediaplayer_record.out").getAbsolutePath();
@@ -97,61 +101,8 @@
}
}
- // Bug 13652927
- public void testVorbisCrash() throws Exception {
- MediaPlayer2 mp = mPlayer;
- MediaPlayer2 mp2 = mPlayer2;
- AssetFileDescriptor afd2 = mResources.openRawResourceFd(R.raw.testmp3_2);
- mp2.setDataSource(new DataSourceDesc.Builder()
- .setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength())
- .build());
- final Monitor onPrepareCalled = new Monitor();
- final Monitor onErrorCalled = new Monitor();
- MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
- @Override
- public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) {
- if (what == MediaPlayer2.MEDIA_INFO_PREPARED) {
- onPrepareCalled.signal();
- }
- }
-
- @Override
- public void onError(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) {
- onErrorCalled.signal();
- }
- };
- mp2.setMediaPlayer2EventCallback(mExecutor, ecb);
- mp2.prepare();
- onPrepareCalled.waitForSignal();
- afd2.close();
- mp2.clearMediaPlayer2EventCallback();
-
- mp2.loopCurrent(true);
- mp2.play();
-
- for (int i = 0; i < 20; i++) {
- try {
- AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.bug13652927);
- mp.setDataSource(new DataSourceDesc.Builder()
- .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
- afd.getLength())
- .build());
- mp.setMediaPlayer2EventCallback(mExecutor, ecb);
- onPrepareCalled.reset();
- mp.prepare();
- onErrorCalled.waitForSignal();
- afd.close();
- } catch (Exception e) {
- // expected to fail
- Log.i("@@@", "failed: " + e);
- }
- Thread.sleep(500);
- assertTrue("media player died",
- mp2.getPlayerState() == MediaPlayerBase.PLAYER_STATE_PLAYING);
- mp.reset();
- }
- }
-
+ @Test
+ @MediumTest
public void testPlayNullSourcePath() throws Exception {
final Monitor onSetDataSourceCalled = new Monitor();
MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
@@ -172,6 +123,8 @@
onSetDataSourceCalled.waitForSignal();
}
+ @Test
+ @LargeTest
public void testPlayAudioFromDataURI() throws Exception {
final int mp3Duration = 34909;
final int tolerance = 70;
@@ -220,9 +173,6 @@
.setLegacyStreamType(AudioManager.STREAM_MUSIC)
.build();
mp.setAudioAttributes(attributes);
- /* FIXME: ensure screen is on while testing.
- mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
- */
assertFalse(mp.getPlayerState() == MediaPlayerBase.PLAYER_STATE_PLAYING);
onPlayCalled.reset();
@@ -284,6 +234,8 @@
}
}
+ @Test
+ @LargeTest
public void testPlayAudio() throws Exception {
final int resid = R.raw.testmp3_2;
final int mp3Duration = 34909;
@@ -414,7 +366,6 @@
.setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
.build();
mp.setAudioAttributes(attributes);
- mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
assertFalse(mp.isPlaying());
onPlayCalled.reset();
@@ -445,6 +396,8 @@
}
*/
+ @Test
+ @LargeTest
public void testPlayAudioLooping() throws Exception {
final int resid = R.raw.testmp3;
@@ -462,8 +415,10 @@
@Override
public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd,
int what, int extra) {
- Log.i("@@@", "got oncompletion");
- onCompletionCalled.signal();
+ if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) {
+ Log.i("@@@", "got oncompletion");
+ onCompletionCalled.signal();
+ }
}
@Override
@@ -500,6 +455,8 @@
}
}
+ @Test
+ @LargeTest
public void testPlayMidi() throws Exception {
final int resid = R.raw.midi8sec;
final int midiDuration = 8000;
@@ -867,6 +824,8 @@
assertEquals(Integer.parseInt(rotation), angle);
}
+ @Test
+ @LargeTest
public void testPlaylist() throws Exception {
if (!checkLoadResource(
R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz)) {
@@ -1452,14 +1411,14 @@
}
}
+ @Test
+ @LargeTest
public void testDeselectTrackForSubtitleTracks() throws Throwable {
if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) {
return; // skip;
}
- /* FIXME: find out counter part of waitForIdleSync.
- getInstrumentation().waitForIdleSync();
- */
+ mInstrumentation.waitForIdleSync();
MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
@Override
@@ -1482,21 +1441,18 @@
mOnDeselectTrackCalled.signal();
}
}
- };
- synchronized (mEventCbLock) {
- mEventCallbacks.add(ecb);
- }
- /* TODO: uncomment once API is available in supportlib.
- mPlayer.setOnSubtitleDataListener(new MediaPlayer2.OnSubtitleDataListener() {
@Override
- public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
+ public void onSubtitleData(
+ MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
if (data != null && data.getData() != null) {
mOnSubtitleDataCalled.signal();
}
}
- });
- */
+ };
+ synchronized (mEventCbLock) {
+ mEventCallbacks.add(ecb);
+ }
mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
@@ -1539,22 +1495,13 @@
mPlayer.reset();
}
+ @Test
+ @LargeTest
public void testChangeSubtitleTrack() throws Throwable {
if (!checkLoadResource(R.raw.testvideo_with_2_subtitle_tracks)) {
return; // skip;
}
- /* TODO: uncomment once API is available in supportlib.
- mPlayer.setOnSubtitleDataListener(new MediaPlayer2.OnSubtitleDataListener() {
- @Override
- public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
- if (data != null && data.getData() != null) {
- mOnSubtitleDataCalled.signal();
- }
- }
- });
- */
-
MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
@Override
public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, int what, int extra) {
@@ -1571,6 +1518,14 @@
mOnPlayCalled.signal();
}
}
+
+ @Override
+ public void onSubtitleData(
+ MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
+ if (data != null && data.getData() != null) {
+ mOnSubtitleDataCalled.signal();
+ }
+ }
};
synchronized (mEventCbLock) {
mEventCallbacks.add(ecb);
@@ -1660,10 +1615,77 @@
mPlayer.reset();
}
+ @Test
+ @LargeTest
+ public void testMediaTimeDiscontinuity() throws Exception {
+ if (!checkLoadResource(
+ R.raw.bbb_s1_320x240_mp4_h264_mp2_800kbps_30fps_aac_lc_5ch_240kbps_44100hz)) {
+ return; // skip
+ }
+
+ final BlockingDeque<MediaTimestamp> timestamps = new LinkedBlockingDeque<>();
+ MediaPlayer2.MediaPlayer2EventCallback ecb = new MediaPlayer2.MediaPlayer2EventCallback() {
+ @Override
+ public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) {
+ if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO) {
+ mOnSeekCompleteCalled.signal();
+ }
+ }
+ @Override
+ public void onMediaTimeDiscontinuity(
+ MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) {
+ timestamps.add(timestamp);
+ mOnMediaTimeDiscontinuityCalled.signal();
+ }
+ };
+ synchronized (mEventCbLock) {
+ mEventCallbacks.add(ecb);
+ }
+
+ mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
+ mPlayer.prepare();
+
+ // Timestamp needs to be reported when playback starts.
+ mOnMediaTimeDiscontinuityCalled.reset();
+ mPlayer.play();
+ do {
+ assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000));
+ } while (Math.abs(timestamps.getLast().getMediaClockRate() - 1.0f) > 0.01f);
+
+ // Timestamp needs to be reported when seeking is done.
+ mOnSeekCompleteCalled.reset();
+ mOnMediaTimeDiscontinuityCalled.reset();
+ mPlayer.seekTo(3000);
+ mOnSeekCompleteCalled.waitForSignal();
+ do {
+ assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000));
+ } while (Math.abs(timestamps.getLast().getMediaClockRate() - 1.0f) > 0.01f);
+
+ // Timestamp needs to be updated when playback rate changes.
+ mOnMediaTimeDiscontinuityCalled.reset();
+ mPlayer.setPlaybackParams(new PlaybackParams().setSpeed(0.5f));
+ mOnMediaTimeDiscontinuityCalled.waitForSignal();
+ do {
+ assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000));
+ } while (Math.abs(timestamps.getLast().getMediaClockRate() - 0.5f) > 0.01f);
+
+ // Timestamp needs to be updated when player is paused.
+ mOnMediaTimeDiscontinuityCalled.reset();
+ mPlayer.pause();
+ mOnMediaTimeDiscontinuityCalled.waitForSignal();
+ do {
+ assertTrue(mOnMediaTimeDiscontinuityCalled.waitForSignal(1000));
+ } while (Math.abs(timestamps.getLast().getMediaClockRate() - 0.0f) > 0.01f);
+
+ mPlayer.reset();
+ }
+
/*
* This test assumes the resources being tested are between 8 and 14 seconds long
* The ones being used here are 10 seconds long.
*/
+ @Test
+ @LargeTest
public void testResumeAtEnd() throws Throwable {
int testsRun = testResumeAtEnd(R.raw.loudsoftmp3)
+ testResumeAtEnd(R.raw.loudsoftwav)
diff --git a/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java b/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java
index 215993a..41fef64 100644
--- a/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java
+++ b/media/src/androidTest/java/androidx/media/MediaPlayer2TestBase.java
@@ -15,20 +15,29 @@
*/
package androidx.media;
+import static android.content.Context.KEYGUARD_SERVICE;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.Instrumentation;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.media.AudioManager;
import android.media.MediaTimestamp;
+import android.media.SubtitleData;
import android.media.TimedMetaData;
import android.net.Uri;
+import android.os.PersistableBundle;
+import android.os.PowerManager;
+import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.view.SurfaceHolder;
+import android.view.WindowManager;
import androidx.annotation.CallSuper;
@@ -41,6 +50,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
@@ -65,6 +75,7 @@
protected Monitor mOnCompletionCalled = new Monitor();
protected Monitor mOnInfoCalled = new Monitor();
protected Monitor mOnErrorCalled = new Monitor();
+ protected Monitor mOnMediaTimeDiscontinuityCalled = new Monitor();
protected int mCallStatus;
protected Context mContext;
@@ -75,34 +86,35 @@
protected MediaPlayer2 mPlayer = null;
protected MediaPlayer2 mPlayer2 = null;
protected MediaStubActivity mActivity;
+ protected Instrumentation mInstrumentation;
protected final Object mEventCbLock = new Object();
- protected List<MediaPlayer2.MediaPlayer2EventCallback> mEventCallbacks =
- new ArrayList<MediaPlayer2.MediaPlayer2EventCallback>();
+ protected List<MediaPlayer2.MediaPlayer2EventCallback> mEventCallbacks = new ArrayList<>();
protected final Object mEventCbLock2 = new Object();
- protected List<MediaPlayer2.MediaPlayer2EventCallback> mEventCallbacks2 =
- new ArrayList<MediaPlayer2.MediaPlayer2EventCallback>();
+ protected List<MediaPlayer2.MediaPlayer2EventCallback> mEventCallbacks2 = new ArrayList<>();
@Rule
public ActivityTestRule<MediaStubActivity> mActivityRule =
new ActivityTestRule<>(MediaStubActivity.class);
+ public PowerManager.WakeLock mScreenLock;
+ private KeyguardManager mKeyguardManager;
// convenience functions to create MediaPlayer2
- protected static MediaPlayer2 createMediaPlayer2(Context context, Uri uri) {
+ protected MediaPlayer2 createMediaPlayer2(Context context, Uri uri) {
return createMediaPlayer2(context, uri, null);
}
- protected static MediaPlayer2 createMediaPlayer2(Context context, Uri uri,
+ protected MediaPlayer2 createMediaPlayer2(Context context, Uri uri,
SurfaceHolder holder) {
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int s = am.generateAudioSessionId();
return createMediaPlayer2(context, uri, holder, null, s > 0 ? s : 0);
}
- protected static MediaPlayer2 createMediaPlayer2(Context context, Uri uri, SurfaceHolder holder,
+ protected MediaPlayer2 createMediaPlayer2(Context context, Uri uri, SurfaceHolder holder,
AudioAttributesCompat audioAttributes, int audioSessionId) {
try {
- MediaPlayer2 mp = MediaPlayer2.create();
+ MediaPlayer2 mp = createMediaPlayer2OnUiThread();
final AudioAttributesCompat aa = audioAttributes != null ? audioAttributes :
new AudioAttributesCompat.Builder().build();
mp.setAudioAttributes(aa);
@@ -144,13 +156,13 @@
return null;
}
- protected static MediaPlayer2 createMediaPlayer2(Context context, int resid) {
+ protected MediaPlayer2 createMediaPlayer2(Context context, int resid) {
AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int s = am.generateAudioSessionId();
return createMediaPlayer2(context, resid, null, s > 0 ? s : 0);
}
- protected static MediaPlayer2 createMediaPlayer2(Context context, int resid,
+ protected MediaPlayer2 createMediaPlayer2(Context context, int resid,
AudioAttributesCompat audioAttributes, int audioSessionId) {
try {
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
@@ -158,7 +170,7 @@
return null;
}
- MediaPlayer2 mp = MediaPlayer2.create();
+ MediaPlayer2 mp = createMediaPlayer2OnUiThread();
final AudioAttributesCompat aa = audioAttributes != null ? audioAttributes :
new AudioAttributesCompat.Builder().build();
@@ -204,6 +216,20 @@
return null;
}
+ private MediaPlayer2 createMediaPlayer2OnUiThread() {
+ final MediaPlayer2[] mp = new MediaPlayer2[1];
+ try {
+ mActivityRule.runOnUiThread(new Runnable() {
+ public void run() {
+ mp[0] = MediaPlayer2.create();
+ }
+ });
+ } catch (Throwable throwable) {
+ fail("Failed to create MediaPlayer2 instance on UI thread.");
+ }
+ return mp[0];
+ }
+
public static class Monitor {
private int mNumSignal;
@@ -258,8 +284,23 @@
@Before
@CallSuper
- public void setUp() throws Exception {
+ public void setUp() throws Throwable {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mKeyguardManager = (KeyguardManager)
+ mInstrumentation.getTargetContext().getSystemService(KEYGUARD_SERVICE);
mActivity = mActivityRule.getActivity();
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Keep screen on while testing.
+ mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ mActivity.setTurnScreenOn(true);
+ mActivity.setShowWhenLocked(true);
+ mKeyguardManager.requestDismissKeyguard(mActivity, null);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
try {
mActivityRule.runOnUiThread(new Runnable() {
public void run() {
@@ -344,11 +385,11 @@
}
@Override
- public void onMediaTimeChanged(MediaPlayer2 mp, DataSourceDesc dsd,
+ public void onMediaTimeDiscontinuity(MediaPlayer2 mp, DataSourceDesc dsd,
MediaTimestamp timestamp) {
synchronized (cbLock) {
for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) {
- ecb.onMediaTimeChanged(mp, dsd, timestamp);
+ ecb.onMediaTimeDiscontinuity(mp, dsd, timestamp);
}
}
}
@@ -361,6 +402,15 @@
}
}
}
+ @Override
+ public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd,
+ final SubtitleData data) {
+ synchronized (cbLock) {
+ for (MediaPlayer2.MediaPlayer2EventCallback ecb : ecbs) {
+ ecb.onSubtitleData(mp, dsd, data);
+ }
+ }
+ }
});
}
@@ -490,11 +540,7 @@
boolean audioOnly = (width != null && width.intValue() == -1)
|| (height != null && height.intValue() == -1);
-
mPlayer.setSurface(mActivity.getSurfaceHolder().getSurface());
- /* FIXME: ensure that screen is on in activity level.
- mPlayer.setScreenOnWhilePlaying(true);
- */
synchronized (mEventCbLock) {
mEventCallbacks.add(new MediaPlayer2.MediaPlayer2EventCallback() {
@@ -566,6 +612,42 @@
Thread.sleep(playTime);
}
+ // validate a few MediaMetrics.
+ PersistableBundle metrics = mPlayer.getMetrics();
+ if (metrics == null) {
+ fail("MediaPlayer.getMetrics() returned null metrics");
+ } else if (metrics.isEmpty()) {
+ fail("MediaPlayer.getMetrics() returned empty metrics");
+ } else {
+
+ int size = metrics.size();
+ Set<String> keys = metrics.keySet();
+
+ if (keys == null) {
+ fail("MediaMetricsSet returned no keys");
+ } else if (keys.size() != size) {
+ fail("MediaMetricsSet.keys().size() mismatch MediaMetricsSet.size()");
+ }
+
+ // we played something; so one of these should be non-null
+ String vmime = metrics.getString(MediaPlayer2.MetricsConstants.MIME_TYPE_VIDEO, null);
+ String amime = metrics.getString(MediaPlayer2.MetricsConstants.MIME_TYPE_AUDIO, null);
+ if (vmime == null && amime == null) {
+ fail("getMetrics() returned neither video nor audio mime value");
+ }
+
+ long duration = metrics.getLong(MediaPlayer2.MetricsConstants.DURATION, -2);
+ if (duration == -2) {
+ fail("getMetrics() didn't return a duration");
+ }
+ long playing = metrics.getLong(MediaPlayer2.MetricsConstants.PLAYING, -2);
+ if (playing == -2) {
+ fail("getMetrics() didn't return a playing time");
+ }
+ if (!keys.contains(MediaPlayer2.MetricsConstants.PLAYING)) {
+ fail("MediaMetricsSet.keys() missing: " + MediaPlayer2.MetricsConstants.PLAYING);
+ }
+ }
mPlayer.reset();
}
diff --git a/media/src/androidTest/java/androidx/media/MediaSession2Test.java b/media/src/androidTest/java/androidx/media/MediaSession2Test.java
index 5e7ed0e..2283ea2 100644
--- a/media/src/androidTest/java/androidx/media/MediaSession2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaSession2Test.java
@@ -200,13 +200,38 @@
}
});
- mPlayer.notifyBufferingState(targetItem, targetBufferingState);
+ mPlayer.notifyBufferingStateChanged(targetItem.getDataSourceDesc(), targetBufferingState);
assertTrue(latchForSessionCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
assertTrue(latchForControllerCallback.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
assertEquals(targetBufferingState, controller.getBufferingState());
}
@Test
+ public void testSeekCompleted() throws Exception {
+ prepareLooper();
+ final long testPosition = 1001;
+ final CountDownLatch latch = new CountDownLatch(1);
+ final SessionCallback callback = new SessionCallback() {
+ @Override
+ public void onSeekCompleted(MediaSession2 session, MediaPlayerBase mpb, long position) {
+ assertEquals(mPlayer, mpb);
+ assertEquals(testPosition, position);
+ latch.countDown();
+ }
+ };
+
+ try (MediaSession2 session = new MediaSession2.Builder(mContext)
+ .setPlayer(mPlayer)
+ .setPlaylistAgent(mMockAgent)
+ .setId("testSeekCompleted")
+ .setSessionCallback(sHandlerExecutor, callback).build()) {
+ mPlayer.mCurrentPosition = testPosition;
+ mPlayer.notifySeekCompleted(testPosition);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+ }
+
+ @Test
public void testCurrentDataSourceChanged() throws Exception {
prepareLooper();
final int listSize = 5;
diff --git a/media/src/androidTest/java/androidx/media/MockPlayer.java b/media/src/androidTest/java/androidx/media/MockPlayer.java
index 49b1a19..19b43fb 100644
--- a/media/src/androidTest/java/androidx/media/MockPlayer.java
+++ b/media/src/androidTest/java/androidx/media/MockPlayer.java
@@ -155,21 +155,6 @@
}
}
- public void notifyBufferingState(final MediaItem2 item, final int bufferingState) {
- mLastBufferingState = bufferingState;
- for (int i = 0; i < mCallbacks.size(); i++) {
- final PlayerEventCallback callback = mCallbacks.keyAt(i);
- final Executor executor = mCallbacks.valueAt(i);
- executor.execute(new Runnable() {
- @Override
- public void run() {
- callback.onBufferingStateChanged(
- MockPlayer.this, item.getDataSourceDesc(), bufferingState);
- }
- });
- }
- }
-
public void notifyCurrentDataSourceChanged(final DataSourceDesc dsd) {
for (int i = 0; i < mCallbacks.size(); i++) {
final PlayerEventCallback callback = mCallbacks.keyAt(i);
@@ -223,6 +208,19 @@
}
}
+ public void notifySeekCompleted(final long position) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ final PlayerEventCallback callback = mCallbacks.keyAt(i);
+ final Executor executor = mCallbacks.valueAt(i);
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ callback.onSeekCompleted(MockPlayer.this, position);
+ }
+ });
+ }
+ }
+
public void notifyError(int what) {
for (int i = 0; i < mCallbacks.size(); i++) {
final PlayerEventCallback callback = mCallbacks.keyAt(i);
diff --git a/media/src/androidTest/java/androidx/media/TestUtils.java b/media/src/androidTest/java/androidx/media/TestUtils.java
index 1e3ba9b..160b392 100644
--- a/media/src/androidTest/java/androidx/media/TestUtils.java
+++ b/media/src/androidTest/java/androidx/media/TestUtils.java
@@ -68,17 +68,28 @@
* incorrect if any bundle contains a bundle.
*/
public static boolean equals(Bundle a, Bundle b) {
+ return contains(a, b) && contains(b, a);
+ }
+
+ /**
+ * Checks whether a Bundle contains another bundle.
+ *
+ * @param a a bundle
+ * @param b another bundle
+ * @return {@code true} if a contains b. {@code false} otherwise. This may be incorrect if any
+ * bundle contains a bundle.
+ */
+ public static boolean contains(Bundle a, Bundle b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
+ return b == null;
+ }
+ if (!a.keySet().containsAll(b.keySet())) {
return false;
}
- if (!a.keySet().containsAll(b.keySet())
- || !b.keySet().containsAll(a.keySet())) {
- return false;
- }
- for (String key : a.keySet()) {
+ for (String key : b.keySet()) {
if (!Objects.equals(a.get(key), b.get(key))) {
return false;
}
diff --git a/media/src/main/java/android/support/v4/media/MediaBrowserCompat.java b/media/src/main/java/android/support/v4/media/MediaBrowserCompat.java
index a0e839b..dab83d8 100644
--- a/media/src/main/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/media/src/main/java/android/support/v4/media/MediaBrowserCompat.java
@@ -1862,7 +1862,7 @@
mCallbacksMessenger = new Messenger(mHandler);
mHandler.setCallbacksMessenger(mCallbacksMessenger);
try {
- mServiceBinderWrapper.registerCallbackMessenger(mCallbacksMessenger);
+ mServiceBinderWrapper.registerCallbackMessenger(mContext, mCallbacksMessenger);
} catch (RemoteException e) {
Log.i(TAG, "Remote error registering client messenger." );
}
@@ -2147,8 +2147,10 @@
sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, data, callbacksMessenger);
}
- void registerCallbackMessenger(Messenger callbackMessenger) throws RemoteException {
+ void registerCallbackMessenger(Context context, Messenger callbackMessenger)
+ throws RemoteException {
Bundle data = new Bundle();
+ data.putString(DATA_PACKAGE_NAME, context.getPackageName());
data.putBundle(DATA_ROOT_HINTS, mRootHints);
sendRequest(CLIENT_MSG_REGISTER_CALLBACK_MESSENGER, data, callbackMessenger);
}
diff --git a/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java b/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
index 1d78fc8..6e35977 100644
--- a/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -31,8 +31,10 @@
import android.media.MediaMetadataRetriever;
import android.media.Rating;
import android.media.RemoteControlClient;
+import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -55,9 +57,12 @@
import android.view.ViewConfiguration;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.core.app.BundleCompat;
+import androidx.media.MediaSessionManager;
+import androidx.media.MediaSessionManager.RemoteUserInfo;
import androidx.media.VolumeProviderCompat;
import androidx.media.session.MediaButtonReceiver;
@@ -383,6 +388,12 @@
// Maximum size of the bitmap in dp.
private static final int MAX_BITMAP_SIZE_IN_DP = 320;
+ private static final String LEGACY_CONTROLLER = "android.media.session.MediaController";
+ private static final String DATA_CALLING_PACKAGE = "data_calling_pkg";
+ private static final String DATA_CALLING_PID = "data_calling_pid";
+ private static final String DATA_CALLING_UID = "data_calling_uid";
+ private static final String DATA_EXTRAS = "data_extras";
+
// Maximum size of the bitmap in px. It shouldn't be changed.
static int sMaxBitmapSize;
@@ -449,7 +460,11 @@
mbrIntent = PendingIntent.getBroadcast(context,
0/* requestCode, ignored */, mediaButtonIntent, 0/* flags */);
}
- if (android.os.Build.VERSION.SDK_INT >= 21) {
+ if (android.os.Build.VERSION.SDK_INT >= 28) {
+ mImpl = new MediaSessionImplApi28(context, tag);
+ // Set default callback to respond to controllers' extra binder requests.
+ setCallback(new Callback() {});
+ } else if (android.os.Build.VERSION.SDK_INT >= 21) {
mImpl = new MediaSessionImplApi21(context, tag);
// Set default callback to respond to controllers' extra binder requests.
setCallback(new Callback() {});
@@ -802,6 +817,20 @@
}
/**
+ * @hide
+ * Gets the controller information who sent the current request.
+ * <p>
+ * Note: This is only valid while in a request callback, such as {@link Callback#onPlay}.
+ *
+ * @throws IllegalStateException If this method is called outside of {@link Callback} methods.
+ * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
+ return mImpl.getCurrentControllerInfo();
+ }
+
+ /**
* Returns the name of the package that sent the last media button, transport control, or
* command from controllers and the system. This is only valid while in a request callback, such
* as {@link Callback#onPlay}. This method is not available and returns null on pre-N devices.
@@ -1822,6 +1851,7 @@
Object getRemoteControlClient();
String getCallingPackage();
+ RemoteUserInfo getCurrentControllerInfo();
}
static class MediaSessionImplBase implements MediaSessionImpl {
@@ -1918,30 +1948,19 @@
}
}
- void postToHandler(int what) {
- postToHandler(what, null);
- }
-
- void postToHandler(int what, int arg1) {
- postToHandler(what, null, arg1);
- }
-
- void postToHandler(int what, Object obj) {
- postToHandler(what, obj, null);
- }
-
- void postToHandler(int what, Object obj, int arg1) {
+ void postToHandler(int what, int arg1, int arg2, Object obj, Bundle extras) {
synchronized (mLock) {
if (mHandler != null) {
- mHandler.post(what, obj, arg1);
- }
- }
- }
-
- void postToHandler(int what, Object obj, Bundle extras) {
- synchronized (mLock) {
- if (mHandler != null) {
- mHandler.post(what, obj, extras);
+ Message msg = mHandler.obtainMessage(what, arg1, arg2, obj);
+ Bundle data = new Bundle();
+ data.putString(DATA_CALLING_PACKAGE, LEGACY_CONTROLLER);
+ data.putInt(DATA_CALLING_PID, Binder.getCallingPid());
+ data.putInt(DATA_CALLING_UID, Binder.getCallingUid());
+ if (extras == null) {
+ data.putBundle(DATA_EXTRAS, extras);
+ }
+ msg.setData(data);
+ msg.sendToTarget();
}
}
}
@@ -2282,6 +2301,16 @@
sendExtras(extras);
}
+ @Override
+ public RemoteUserInfo getCurrentControllerInfo() {
+ synchronized (mLock) {
+ if (mHandler != null) {
+ return mHandler.getRemoteUserInfo();
+ }
+ }
+ return null;
+ }
+
// Registers/unregisters components as needed.
boolean update() {
boolean registeredRcc = false;
@@ -2792,6 +2821,26 @@
public boolean isTransportControlEnabled() {
return (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0;
}
+
+ void postToHandler(int what) {
+ MediaSessionImplBase.this.postToHandler(what, 0, 0, null, null);
+ }
+
+ void postToHandler(int what, int arg1) {
+ MediaSessionImplBase.this.postToHandler(what, arg1, 0, null, null);
+ }
+
+ void postToHandler(int what, Object obj) {
+ MediaSessionImplBase.this.postToHandler(what, 0, 0, obj, null);
+ }
+
+ void postToHandler(int what, Object obj, int arg1) {
+ MediaSessionImplBase.this.postToHandler(what, arg1, 0, obj, null);
+ }
+
+ void postToHandler(int what, Object obj, Bundle extras) {
+ MediaSessionImplBase.this.postToHandler(what, 0, 0, obj, extras);
+ }
}
private static final class Command {
@@ -2843,138 +2892,133 @@
private static final int KEYCODE_MEDIA_PAUSE = 127;
private static final int KEYCODE_MEDIA_PLAY = 126;
+ private RemoteUserInfo mRemoteUserInfo;
+
public MessageHandler(Looper looper) {
super(looper);
}
- public void post(int what, Object obj, Bundle bundle) {
- Message msg = obtainMessage(what, obj);
- msg.setData(bundle);
- msg.sendToTarget();
- }
-
- public void post(int what, Object obj) {
- obtainMessage(what, obj).sendToTarget();
- }
-
- public void post(int what) {
- post(what, null);
- }
-
- public void post(int what, Object obj, int arg1) {
- obtainMessage(what, arg1, 0, obj).sendToTarget();
- }
-
@Override
public void handleMessage(Message msg) {
MediaSessionCompat.Callback cb = mCallback;
if (cb == null) {
return;
}
- switch (msg.what) {
- case MSG_COMMAND:
- Command cmd = (Command) msg.obj;
- cb.onCommand(cmd.command, cmd.extras, cmd.stub);
- break;
- case MSG_MEDIA_BUTTON:
- KeyEvent keyEvent = (KeyEvent) msg.obj;
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
- // Let the Callback handle events first before using the default behavior
- if (!cb.onMediaButtonEvent(intent)) {
- onMediaButtonEvent(keyEvent, cb);
- }
- break;
- case MSG_PREPARE:
- cb.onPrepare();
- break;
- case MSG_PREPARE_MEDIA_ID:
- cb.onPrepareFromMediaId((String) msg.obj, msg.getData());
- break;
- case MSG_PREPARE_SEARCH:
- cb.onPrepareFromSearch((String) msg.obj, msg.getData());
- break;
- case MSG_PREPARE_URI:
- cb.onPrepareFromUri((Uri) msg.obj, msg.getData());
- break;
- case MSG_PLAY:
- cb.onPlay();
- break;
- case MSG_PLAY_MEDIA_ID:
- cb.onPlayFromMediaId((String) msg.obj, msg.getData());
- break;
- case MSG_PLAY_SEARCH:
- cb.onPlayFromSearch((String) msg.obj, msg.getData());
- break;
- case MSG_PLAY_URI:
- cb.onPlayFromUri((Uri) msg.obj, msg.getData());
- break;
- case MSG_SKIP_TO_ITEM:
- cb.onSkipToQueueItem((Long) msg.obj);
- break;
- case MSG_PAUSE:
- cb.onPause();
- break;
- case MSG_STOP:
- cb.onStop();
- break;
- case MSG_NEXT:
- cb.onSkipToNext();
- break;
- case MSG_PREVIOUS:
- cb.onSkipToPrevious();
- break;
- case MSG_FAST_FORWARD:
- cb.onFastForward();
- break;
- case MSG_REWIND:
- cb.onRewind();
- break;
- case MSG_SEEK_TO:
- cb.onSeekTo((Long) msg.obj);
- break;
- case MSG_RATE:
- cb.onSetRating((RatingCompat) msg.obj);
- break;
- case MSG_RATE_EXTRA:
- cb.onSetRating((RatingCompat) msg.obj, msg.getData());
- break;
- case MSG_CUSTOM_ACTION:
- cb.onCustomAction((String) msg.obj, msg.getData());
- break;
- case MSG_ADD_QUEUE_ITEM:
- cb.onAddQueueItem((MediaDescriptionCompat) msg.obj);
- break;
- case MSG_ADD_QUEUE_ITEM_AT:
- cb.onAddQueueItem((MediaDescriptionCompat) msg.obj, msg.arg1);
- break;
- case MSG_REMOVE_QUEUE_ITEM:
- cb.onRemoveQueueItem((MediaDescriptionCompat) msg.obj);
- break;
- case MSG_REMOVE_QUEUE_ITEM_AT:
- if (mQueue != null) {
- QueueItem item = (msg.arg1 >= 0 && msg.arg1 < mQueue.size())
- ? mQueue.get(msg.arg1) : null;
- if (item != null) {
- cb.onRemoveQueueItem(item.getDescription());
+
+ Bundle data = msg.getData();
+ mRemoteUserInfo = new RemoteUserInfo(data.getString(DATA_CALLING_PACKAGE),
+ data.getInt(DATA_CALLING_PID), data.getInt(DATA_CALLING_UID));
+ data = data.getBundle(DATA_EXTRAS);
+
+ try {
+ switch (msg.what) {
+ case MSG_COMMAND:
+ Command cmd = (Command) msg.obj;
+ cb.onCommand(cmd.command, cmd.extras, cmd.stub);
+ break;
+ case MSG_MEDIA_BUTTON:
+ KeyEvent keyEvent = (KeyEvent) msg.obj;
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ // Let the Callback handle events first before using the default
+ // behavior
+ if (!cb.onMediaButtonEvent(intent)) {
+ onMediaButtonEvent(keyEvent, cb);
}
- }
- break;
- case MSG_ADJUST_VOLUME:
- adjustVolume(msg.arg1, 0);
- break;
- case MSG_SET_VOLUME:
- setVolumeTo(msg.arg1, 0);
- break;
- case MSG_SET_CAPTIONING_ENABLED:
- cb.onSetCaptioningEnabled((boolean) msg.obj);
- break;
- case MSG_SET_REPEAT_MODE:
- cb.onSetRepeatMode(msg.arg1);
- break;
- case MSG_SET_SHUFFLE_MODE:
- cb.onSetShuffleMode(msg.arg1);
- break;
+ break;
+ case MSG_PREPARE:
+ cb.onPrepare();
+ break;
+ case MSG_PREPARE_MEDIA_ID:
+ cb.onPrepareFromMediaId((String) msg.obj, data);
+ break;
+ case MSG_PREPARE_SEARCH:
+ cb.onPrepareFromSearch((String) msg.obj, data);
+ break;
+ case MSG_PREPARE_URI:
+ cb.onPrepareFromUri((Uri) msg.obj, data);
+ break;
+ case MSG_PLAY:
+ cb.onPlay();
+ break;
+ case MSG_PLAY_MEDIA_ID:
+ cb.onPlayFromMediaId((String) msg.obj, data);
+ break;
+ case MSG_PLAY_SEARCH:
+ cb.onPlayFromSearch((String) msg.obj, data);
+ break;
+ case MSG_PLAY_URI:
+ cb.onPlayFromUri((Uri) msg.obj, data);
+ break;
+ case MSG_SKIP_TO_ITEM:
+ cb.onSkipToQueueItem((Long) msg.obj);
+ break;
+ case MSG_PAUSE:
+ cb.onPause();
+ break;
+ case MSG_STOP:
+ cb.onStop();
+ break;
+ case MSG_NEXT:
+ cb.onSkipToNext();
+ break;
+ case MSG_PREVIOUS:
+ cb.onSkipToPrevious();
+ break;
+ case MSG_FAST_FORWARD:
+ cb.onFastForward();
+ break;
+ case MSG_REWIND:
+ cb.onRewind();
+ break;
+ case MSG_SEEK_TO:
+ cb.onSeekTo((Long) msg.obj);
+ break;
+ case MSG_RATE:
+ cb.onSetRating((RatingCompat) msg.obj);
+ break;
+ case MSG_RATE_EXTRA:
+ cb.onSetRating((RatingCompat) msg.obj, data);
+ break;
+ case MSG_CUSTOM_ACTION:
+ cb.onCustomAction((String) msg.obj, data);
+ break;
+ case MSG_ADD_QUEUE_ITEM:
+ cb.onAddQueueItem((MediaDescriptionCompat) msg.obj);
+ break;
+ case MSG_ADD_QUEUE_ITEM_AT:
+ cb.onAddQueueItem((MediaDescriptionCompat) msg.obj, msg.arg1);
+ break;
+ case MSG_REMOVE_QUEUE_ITEM:
+ cb.onRemoveQueueItem((MediaDescriptionCompat) msg.obj);
+ break;
+ case MSG_REMOVE_QUEUE_ITEM_AT:
+ if (mQueue != null) {
+ QueueItem item = (msg.arg1 >= 0 && msg.arg1 < mQueue.size())
+ ? mQueue.get(msg.arg1) : null;
+ if (item != null) {
+ cb.onRemoveQueueItem(item.getDescription());
+ }
+ }
+ break;
+ case MSG_ADJUST_VOLUME:
+ adjustVolume(msg.arg1, 0);
+ break;
+ case MSG_SET_VOLUME:
+ setVolumeTo(msg.arg1, 0);
+ break;
+ case MSG_SET_CAPTIONING_ENABLED:
+ cb.onSetCaptioningEnabled((boolean) msg.obj);
+ break;
+ case MSG_SET_REPEAT_MODE:
+ cb.onSetRepeatMode(msg.arg1);
+ break;
+ case MSG_SET_SHUFFLE_MODE:
+ cb.onSetShuffleMode(msg.arg1);
+ break;
+ }
+ } finally {
+ mRemoteUserInfo = null;
}
}
@@ -3028,6 +3072,10 @@
break;
}
}
+
+ RemoteUserInfo getRemoteUserInfo() {
+ return mRemoteUserInfo;
+ }
}
}
@@ -3050,7 +3098,8 @@
new RemoteControlClient.OnPlaybackPositionUpdateListener() {
@Override
public void onPlaybackPositionUpdate(long newPositionMs) {
- postToHandler(MessageHandler.MSG_SEEK_TO, newPositionMs);
+ postToHandler(
+ MessageHandler.MSG_SEEK_TO, -1, -1, newPositionMs, null);
}
};
mRcc.setPlaybackPositionUpdateListener(listener);
@@ -3135,8 +3184,8 @@
public void onMetadataUpdate(int key, Object newValue) {
if (key == MediaMetadataEditor.RATING_KEY_BY_USER
&& newValue instanceof Rating) {
- postToHandler(MessageHandler.MSG_RATE,
- RatingCompat.fromRating(newValue));
+ postToHandler(MessageHandler.MSG_RATE, -1, -1,
+ RatingCompat.fromRating(newValue), null);
}
}
};
@@ -3410,6 +3459,11 @@
}
}
+ @Override
+ public RemoteUserInfo getCurrentControllerInfo() {
+ return null;
+ }
+
class ExtraSession extends IMediaSession.Stub {
@Override
public void sendCommand(String command, Bundle args, ResultReceiverWrapper cb) {
@@ -3703,4 +3757,25 @@
}
}
}
+
+ @RequiresApi(28)
+ static class MediaSessionImplApi28 extends MediaSessionImplApi21 {
+ private MediaSession mSession;
+
+ MediaSessionImplApi28(Context context, String tag) {
+ super(context, tag);
+ }
+
+ MediaSessionImplApi28(Object mediaSession) {
+ super(mediaSession);
+ mSession = (MediaSession) mediaSession;
+ }
+
+ @Override
+ public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
+ android.media.session.MediaSessionManager.RemoteUserInfo info =
+ mSession.getCurrentControllerInfo();
+ return new RemoteUserInfo(info.getPackageName(), info.getPid(), info.getUid());
+ }
+ }
}
diff --git a/media/src/main/java/androidx/media/MediaBrowser2.java b/media/src/main/java/androidx/media/MediaBrowser2.java
index 6ef7fcf..04f666e 100644
--- a/media/src/main/java/androidx/media/MediaBrowser2.java
+++ b/media/src/main/java/androidx/media/MediaBrowser2.java
@@ -19,6 +19,7 @@
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import android.content.Context;
+import android.os.BadParcelableException;
import android.os.Bundle;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaBrowserCompat.ItemCallback;
@@ -195,13 +196,20 @@
}
});
} else {
- MediaBrowserCompat newBrowser = new MediaBrowserCompat(getContext(),
- getSessionToken().getComponentName(), new GetLibraryRootCallback(extras),
- extras);
- newBrowser.connect();
- synchronized (mLock) {
- mBrowserCompats.put(extras, newBrowser);
- }
+ getCallbackExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ // Do this on the callback executor to set the looper of MediaBrowserCompat's
+ // callback handler to this looper.
+ MediaBrowserCompat newBrowser = new MediaBrowserCompat(getContext(),
+ getSessionToken().getComponentName(),
+ new GetLibraryRootCallback(extras), extras);
+ synchronized (mLock) {
+ mBrowserCompats.put(extras, newBrowser);
+ }
+ newBrowser.connect();
+ }
+ });
}
}
@@ -218,16 +226,17 @@
if (parentId == null) {
throw new IllegalArgumentException("parentId shouldn't be null");
}
- // TODO: Document this behavior
- Bundle option;
- if (extras != null && (extras.containsKey(MediaBrowserCompat.EXTRA_PAGE)
- || extras.containsKey(MediaBrowserCompat.EXTRA_PAGE_SIZE))) {
- option = new Bundle(extras);
- option.remove(MediaBrowserCompat.EXTRA_PAGE);
- option.remove(MediaBrowserCompat.EXTRA_PAGE_SIZE);
- } else {
- option = extras;
+ // TODO: Revisit using default browser is OK. Here's my concern.
+ // Assume that MediaBrowser2 is connected with the MediaBrowserServiceCompat.
+ // Since MediaBrowserServiceCompat can call MediaBrowserServiceCompat#
+ // getBrowserRootHints(), the service may refuse calls from MediaBrowser2.
+ // It may be safe because there's not much app that implements MediaBrowserService
+ // for sharing contents.
+ MediaBrowserCompat browser = getBrowserCompat();
+ if (browser == null) {
+ return;
}
+ // TODO: Document that this API creates new SubscriptionCallback for each calls.
SubscribeCallback callback = new SubscribeCallback();
synchronized (mLock) {
List<SubscribeCallback> list = mSubscribeCallbacks.get(parentId);
@@ -237,11 +246,11 @@
}
list.add(callback);
}
- // TODO: Revisit using default browser is OK. Here's my concern.
- // Assume that MediaBrowser2 is connected with the MediaBrowserServiceCompat.
- // Since MediaBrowserServiceCompat can call MediaBrowserServiceCompat#
- // getBrowserRootHints(), the service may refuse calls from MediaBrowser2
- getBrowserCompat().subscribe(parentId, option, callback);
+ if (extras == null) {
+ browser.subscribe(parentId, callback);
+ } else {
+ browser.subscribe(parentId, extras, callback);
+ }
}
/**
@@ -257,6 +266,10 @@
if (parentId == null) {
throw new IllegalArgumentException("parentId shouldn't be null");
}
+ MediaBrowserCompat browser = getBrowserCompat();
+ if (browser == null) {
+ return;
+ }
// Note: don't use MediaBrowserCompat#unsubscribe(String) here, to keep the subscription
// callback for getChildren.
synchronized (mLock) {
@@ -264,7 +277,6 @@
if (list == null) {
return;
}
- MediaBrowserCompat browser = getBrowserCompat();
for (int i = 0; i < list.size(); i++) {
browser.unsubscribe(parentId, list.get(i));
}
@@ -288,12 +300,16 @@
if (page < 1 || pageSize < 1) {
throw new IllegalArgumentException("Neither page nor pageSize should be less than 1");
}
- Bundle options = new Bundle(extras);
+ MediaBrowserCompat browser = getBrowserCompat();
+ if (browser == null) {
+ return;
+ }
+
+ Bundle options = MediaUtils2.createBundle(extras);
options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
// TODO: Revisit using default browser is OK. See TODO in subscribe
- getBrowserCompat().subscribe(parentId, options,
- new GetChildrenCallback(parentId, page, pageSize));
+ browser.subscribe(parentId, options, new GetChildrenCallback(parentId, page, pageSize));
}
/**
@@ -304,7 +320,11 @@
*/
public void getItem(@NonNull final String mediaId) {
// TODO: Revisit using default browser is OK. See TODO in subscribe
- getBrowserCompat().getItem(mediaId, new ItemCallback() {
+ MediaBrowserCompat browser = getBrowserCompat();
+ if (browser == null) {
+ return;
+ }
+ browser.getItem(mediaId, new ItemCallback() {
@Override
public void onItemLoaded(final MediaItem item) {
getCallbackExecutor().execute(new Runnable() {
@@ -367,6 +387,20 @@
}
}
+ private Bundle getExtrasWithoutPagination(Bundle extras) {
+ if (extras == null) {
+ return null;
+ }
+ extras.setClassLoader(getContext().getClassLoader());
+ try {
+ extras.remove(MediaBrowserCompat.EXTRA_PAGE);
+ extras.remove(MediaBrowserCompat.EXTRA_PAGE_SIZE);
+ } catch (BadParcelableException e) {
+ // Pass through...
+ }
+ return extras;
+ }
+
private class GetLibraryRootCallback extends MediaBrowserCompat.ConnectionCallback {
private final Bundle mExtras;
@@ -472,7 +506,7 @@
@Override
public void onChildrenLoaded(final String parentId, List<MediaItem> children,
- final Bundle options) {
+ Bundle options) {
final List<MediaItem2> items;
if (children == null) {
items = null;
@@ -482,12 +516,17 @@
items.add(MediaUtils2.createMediaItem2(children.get(i)));
}
}
+ final Bundle extras = getExtrasWithoutPagination(options);
getCallbackExecutor().execute(new Runnable() {
@Override
public void run() {
+ MediaBrowserCompat browser = getBrowserCompat();
+ if (browser == null) {
+ return;
+ }
getCallback().onGetChildrenDone(MediaBrowser2.this, parentId, mPage, mPageSize,
- items, options);
- getBrowserCompat().unsubscribe(mParentId, GetChildrenCallback.this);
+ items, extras);
+ browser.unsubscribe(mParentId, GetChildrenCallback.this);
}
});
}
diff --git a/media/src/main/java/androidx/media/MediaBrowserProtocol.java b/media/src/main/java/androidx/media/MediaBrowserProtocol.java
index 5c85880..02e0014 100644
--- a/media/src/main/java/androidx/media/MediaBrowserProtocol.java
+++ b/media/src/main/java/androidx/media/MediaBrowserProtocol.java
@@ -29,6 +29,7 @@
public static final String DATA_CALLBACK_TOKEN = "data_callback_token";
public static final String DATA_CALLING_UID = "data_calling_uid";
+ public static final String DATA_CALLING_PID = "data_calling_pid";
public static final String DATA_MEDIA_ITEM_ID = "data_media_item_id";
public static final String DATA_MEDIA_ITEM_LIST = "data_media_item_list";
public static final String DATA_MEDIA_SESSION_TOKEN = "data_media_session_token";
diff --git a/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java b/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java
index 8f24837..aa8392f 100644
--- a/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java
+++ b/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java
@@ -17,6 +17,7 @@
package androidx.media;
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static androidx.media.MediaBrowserProtocol.CLIENT_MSG_ADD_SUBSCRIPTION;
import static androidx.media.MediaBrowserProtocol.CLIENT_MSG_CONNECT;
import static androidx.media.MediaBrowserProtocol.CLIENT_MSG_DISCONNECT;
@@ -27,6 +28,7 @@
import static androidx.media.MediaBrowserProtocol.CLIENT_MSG_SEND_CUSTOM_ACTION;
import static androidx.media.MediaBrowserProtocol.CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER;
import static androidx.media.MediaBrowserProtocol.DATA_CALLBACK_TOKEN;
+import static androidx.media.MediaBrowserProtocol.DATA_CALLING_PID;
import static androidx.media.MediaBrowserProtocol.DATA_CALLING_UID;
import static androidx.media.MediaBrowserProtocol.DATA_CUSTOM_ACTION;
import static androidx.media.MediaBrowserProtocol.DATA_CUSTOM_ACTION_EXTRAS;
@@ -61,6 +63,7 @@
import android.os.Messenger;
import android.os.Parcel;
import android.os.RemoteException;
+import android.service.media.MediaBrowserService;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.session.IMediaSession;
import android.support.v4.media.session.MediaSessionCompat;
@@ -76,6 +79,7 @@
import androidx.collection.ArrayMap;
import androidx.core.app.BundleCompat;
import androidx.core.util.Pair;
+import androidx.media.MediaSessionManager.RemoteUserInfo;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -167,9 +171,10 @@
/** @hide */
@RestrictTo(LIBRARY)
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
- RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED, RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED })
- private @interface ResultFlags { }
+ @IntDef(flag = true, value = {RESULT_FLAG_OPTION_NOT_HANDLED,
+ RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED, RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED})
+ private @interface ResultFlags {
+ }
final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
ConnectionRecord mCurConnection;
@@ -182,6 +187,7 @@
void setSessionToken(MediaSessionCompat.Token token);
void notifyChildrenChanged(final String parentId, final Bundle options);
Bundle getBrowserRootHints();
+ RemoteUserInfo getCurrentBrowserInfo();
}
class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl {
@@ -206,7 +212,7 @@
@Override
public void run() {
Iterator<ConnectionRecord> iter = mConnections.values().iterator();
- while (iter.hasNext()){
+ while (iter.hasNext()) {
ConnectionRecord connection = iter.next();
try {
connection.callbacks.onConnect(connection.root.getRootId(), token,
@@ -246,10 +252,19 @@
public Bundle getBrowserRootHints() {
if (mCurConnection == null) {
throw new IllegalStateException("This should be called inside of onLoadChildren,"
- + " onLoadItem or onSearch methods");
+ + " onLoadItem, onSearch, or onCustomAction methods");
}
return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
}
+
+ @Override
+ public RemoteUserInfo getCurrentBrowserInfo() {
+ if (mCurConnection == null) {
+ throw new IllegalStateException("This should be called inside of onLoadChildren,"
+ + " onLoadItem, onSearch, or onCustomAction methods");
+ }
+ return mCurConnection.browserInfo;
+ }
}
@RequiresApi(21)
@@ -298,19 +313,6 @@
}
@Override
- public Bundle getBrowserRootHints() {
- if (mMessenger == null) {
- // TODO: Handle getBrowserRootHints when connected with framework MediaBrowser.
- return null;
- }
- if (mCurConnection == null) {
- throw new IllegalStateException("This should be called inside of onLoadChildren,"
- + " onLoadItem or onSearch methods");
- }
- return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
- }
-
- @Override
public MediaBrowserServiceCompatApi21.BrowserRoot onGetRoot(
String clientPackageName, int clientUid, Bundle rootHints) {
Bundle rootExtras = null;
@@ -393,6 +395,28 @@
}
});
}
+
+ @Override
+ public Bundle getBrowserRootHints() {
+ if (mMessenger == null) {
+ // TODO: Handle getBrowserRootHints when connected with framework MediaBrowser.
+ return null;
+ }
+ if (mCurConnection == null) {
+ throw new IllegalStateException("This should be called inside of onLoadChildren,"
+ + " onLoadItem, onSearch, or onCustomAction methods");
+ }
+ return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
+ }
+
+ @Override
+ public RemoteUserInfo getCurrentBrowserInfo() {
+ if (mCurConnection == null) {
+ throw new IllegalStateException("This should be called inside of onLoadChildren,"
+ + " onLoadItem, onSearch, or onCustomAction methods");
+ }
+ return mCurConnection.browserInfo;
+ }
}
@RequiresApi(23)
@@ -488,6 +512,17 @@
}
}
+ @RequiresApi(28)
+ class MediaBrowserServiceImplApi28 extends MediaBrowserServiceImplApi26 {
+ @Override
+ public RemoteUserInfo getCurrentBrowserInfo() {
+ android.media.session.MediaSessionManager.RemoteUserInfo userInfoObj =
+ ((MediaBrowserService) mServiceObj).getCurrentBrowserInfo();
+ return new RemoteUserInfo(
+ userInfoObj.getPackageName(), userInfoObj.getPid(), userInfoObj.getUid());
+ }
+ }
+
private final class ServiceHandler extends Handler {
private final ServiceBinderImpl mServiceBinderImpl = new ServiceBinderImpl();
@@ -500,7 +535,8 @@
switch (msg.what) {
case CLIENT_MSG_CONNECT:
mServiceBinderImpl.connect(data.getString(DATA_PACKAGE_NAME),
- data.getInt(DATA_CALLING_UID), data.getBundle(DATA_ROOT_HINTS),
+ data.getInt(DATA_CALLING_PID), data.getInt(DATA_CALLING_UID),
+ data.getBundle(DATA_ROOT_HINTS),
new ServiceCallbacksCompat(msg.replyTo));
break;
case CLIENT_MSG_DISCONNECT:
@@ -524,7 +560,8 @@
break;
case CLIENT_MSG_REGISTER_CALLBACK_MESSENGER:
mServiceBinderImpl.registerCallbacks(new ServiceCallbacksCompat(msg.replyTo),
- data.getBundle(DATA_ROOT_HINTS));
+ data.getString(DATA_PACKAGE_NAME), data.getInt(DATA_CALLING_PID),
+ data.getInt(DATA_CALLING_UID), data.getBundle(DATA_ROOT_HINTS));
break;
case CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER:
mServiceBinderImpl.unregisterCallbacks(new ServiceCallbacksCompat(msg.replyTo));
@@ -555,6 +592,7 @@
Bundle data = msg.getData();
data.setClassLoader(MediaBrowserCompat.class.getClassLoader());
data.putInt(DATA_CALLING_UID, Binder.getCallingUid());
+ data.putInt(DATA_CALLING_PID, Binder.getCallingPid());
return super.sendMessageAtTime(msg, uptimeMillis);
}
@@ -571,13 +609,23 @@
* All the info about a connection.
*/
private class ConnectionRecord implements IBinder.DeathRecipient {
- String pkg;
- Bundle rootHints;
- ServiceCallbacks callbacks;
- BrowserRoot root;
- HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
+ public final String pkg;
+ public final int pid;
+ public final int uid;
+ public final RemoteUserInfo browserInfo;
+ public final Bundle rootHints;
+ public final ServiceCallbacks callbacks;
+ public final HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
+ public BrowserRoot root;
- ConnectionRecord() {
+ ConnectionRecord(String pkg, int pid, int uid, Bundle rootHints,
+ ServiceCallbacks callback) {
+ this.pkg = pkg;
+ this.pid = pid;
+ this.uid = uid;
+ this.browserInfo = new RemoteUserInfo(pkg, pid, uid);
+ this.rootHints = rootHints;
+ this.callbacks = callback;
}
@Override
@@ -740,7 +788,7 @@
ServiceBinderImpl() {
}
- public void connect(final String pkg, final int uid, final Bundle rootHints,
+ public void connect(final String pkg, final int pid, final int uid, final Bundle rootHints,
final ServiceCallbacks callbacks) {
if (!isValidPackage(pkg, uid)) {
@@ -756,13 +804,11 @@
// Clear out the old subscriptions. We are getting new ones.
mConnections.remove(b);
- final ConnectionRecord connection = new ConnectionRecord();
- connection.pkg = pkg;
- connection.rootHints = rootHints;
- connection.callbacks = callbacks;
-
- connection.root =
- MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints);
+ final ConnectionRecord connection = new ConnectionRecord(pkg, pid, uid,
+ rootHints, callbacks);
+ mCurConnection = connection;
+ connection.root = MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints);
+ mCurConnection = null;
// If they didn't return something, don't allow this client.
if (connection.root == null) {
@@ -872,7 +918,8 @@
}
// Used when {@link MediaBrowserProtocol#EXTRA_MESSENGER_BINDER} is used.
- public void registerCallbacks(final ServiceCallbacks callbacks, final Bundle rootHints) {
+ public void registerCallbacks(final ServiceCallbacks callbacks, final String pkg,
+ final int pid, final int uid, final Bundle rootHints) {
mHandler.postOrRun(new Runnable() {
@Override
public void run() {
@@ -880,9 +927,8 @@
// Clear out the old subscriptions. We are getting new ones.
mConnections.remove(b);
- final ConnectionRecord connection = new ConnectionRecord();
- connection.callbacks = callbacks;
- connection.rootHints = rootHints;
+ final ConnectionRecord connection = new ConnectionRecord(pkg, pid, uid,
+ rootHints, callbacks);
mConnections.put(b, connection);
try {
b.linkToDeath(connection, 0);
@@ -1031,7 +1077,9 @@
@Override
public void onCreate() {
super.onCreate();
- if (Build.VERSION.SDK_INT >= 26) {
+ if (Build.VERSION.SDK_INT >= 28) {
+ mImpl = new MediaBrowserServiceImplApi28();
+ } else if (Build.VERSION.SDK_INT >= 26) {
mImpl = new MediaBrowserServiceImplApi26();
} else if (Build.VERSION.SDK_INT >= 23) {
mImpl = new MediaBrowserServiceImplApi23();
@@ -1253,6 +1301,23 @@
}
/**
+ * @hide
+ * Gets the browser information who sent the current request.
+ *
+ * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
+ * {@link #onLoadChildren} or {@link #onLoadItem}.
+ * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
+ */
+ @RestrictTo(LIBRARY_GROUP)
+ public final RemoteUserInfo getCurrentBrowserInfo() {
+ if (mCurConnection == null) {
+ throw new IllegalStateException("This should be called inside of onGetRoot or"
+ + " onLoadChildren or onLoadItem methods");
+ }
+ return mImpl.getCurrentBrowserInfo();
+ }
+
+ /**
* Notifies all connected media browsers that the children of
* the specified parent id have changed in some way.
* This will cause browsers to fetch subscribed content again.
diff --git a/media/src/main/java/androidx/media/MediaConstants2.java b/media/src/main/java/androidx/media/MediaConstants2.java
index 68a9a19..6f1132a 100644
--- a/media/src/main/java/androidx/media/MediaConstants2.java
+++ b/media/src/main/java/androidx/media/MediaConstants2.java
@@ -33,8 +33,10 @@
"androidx.media.session.event.ON_PLAYBACK_INFO_CHANGED";
static final String SESSION_EVENT_ON_PLAYBACK_SPEED_CHANGED =
"androidx.media.session.event.ON_PLAYBACK_SPEED_CHANGED";
- static final String SESSION_EVENT_ON_BUFFERING_STATE_CHAGNED =
+ static final String SESSION_EVENT_ON_BUFFERING_STATE_CHANGED =
"androidx.media.session.event.ON_BUFFERING_STATE_CHANGED";
+ static final String SESSION_EVENT_ON_SEEK_COMPLETED =
+ "androidx.media.session.event.ON_SEEK_COMPLETED";
static final String SESSION_EVENT_ON_REPEAT_MODE_CHANGED =
"androidx.media.session.event.ON_REPEAT_MODE_CHANGED";
static final String SESSION_EVENT_ON_SHUFFLE_MODE_CHANGED =
diff --git a/media/src/main/java/androidx/media/MediaController2.java b/media/src/main/java/androidx/media/MediaController2.java
index 1da552d..027178c 100644
--- a/media/src/main/java/androidx/media/MediaController2.java
+++ b/media/src/main/java/androidx/media/MediaController2.java
@@ -58,7 +58,7 @@
import static androidx.media.MediaConstants2.CONTROLLER_COMMAND_CONNECT;
import static androidx.media.MediaConstants2.CONTROLLER_COMMAND_DISCONNECT;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED;
-import static androidx.media.MediaConstants2.SESSION_EVENT_ON_BUFFERING_STATE_CHAGNED;
+import static androidx.media.MediaConstants2.SESSION_EVENT_ON_BUFFERING_STATE_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_CURRENT_MEDIA_ITEM_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ERROR;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED;
@@ -68,6 +68,7 @@
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYLIST_METADATA_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_REPEAT_MODE_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ROUTES_INFO_CHANGED;
+import static androidx.media.MediaConstants2.SESSION_EVENT_ON_SEEK_COMPLETED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_SHUFFLE_MODE_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_SEND_CUSTOM_COMMAND;
import static androidx.media.MediaConstants2.SESSION_EVENT_SET_CUSTOM_LAYOUT;
@@ -130,6 +131,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
+import androidx.annotation.VisibleForTesting;
import androidx.media.MediaPlaylistAgent.RepeatMode;
import androidx.media.MediaPlaylistAgent.ShuffleMode;
import androidx.media.MediaSession2.CommandButton;
@@ -542,8 +544,14 @@
}
case SESSION_EVENT_ON_PLAYER_STATE_CHANGED: {
int playerState = extras.getInt(ARGUMENT_PLAYER_STATE);
+ PlaybackStateCompat state =
+ extras.getParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT);
+ if (state == null) {
+ return;
+ }
synchronized (mLock) {
mPlayerState = playerState;
+ mPlaybackStateCompat = state;
}
mCallback.onPlayerStateChanged(MediaController2.this, playerState);
break;
@@ -653,18 +661,33 @@
MediaController2.this, state.getPlaybackSpeed());
break;
}
- case SESSION_EVENT_ON_BUFFERING_STATE_CHAGNED: {
+ case SESSION_EVENT_ON_BUFFERING_STATE_CHANGED: {
MediaItem2 item = MediaItem2.fromBundle(extras.getBundle(ARGUMENT_MEDIA_ITEM));
int bufferingState = extras.getInt(ARGUMENT_BUFFERING_STATE);
- if (item == null) {
+ PlaybackStateCompat state =
+ extras.getParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT);
+ if (item == null || state == null) {
return;
}
synchronized (mLock) {
mBufferingState = bufferingState;
+ mPlaybackStateCompat = state;
}
mCallback.onBufferingStateChanged(MediaController2.this, item, bufferingState);
break;
}
+ case SESSION_EVENT_ON_SEEK_COMPLETED: {
+ long position = extras.getLong(ARGUMENT_SEEK_POSITION);
+ PlaybackStateCompat state =
+ extras.getParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT);
+ if (state == null) {
+ return;
+ }
+ synchronized (mLock) {
+ mPlaybackStateCompat = state;
+ }
+ mCallback.onSeekCompleted(MediaController2.this, position);
+ }
}
}
}
@@ -723,6 +746,9 @@
@GuardedBy("mLock")
private MediaMetadataCompat mMediaMetadataCompat;
+ // For testing.
+ private Long mTimeDiff;
+
// Assignment should be used with the lock hold, but should be used without a lock to prevent
// potential deadlock.
@GuardedBy("mLock")
@@ -1197,7 +1223,7 @@
return UNKNOWN_TIME;
}
if (mPlaybackStateCompat != null) {
- long timeDiff = SystemClock.elapsedRealtime()
+ long timeDiff = (mTimeDiff != null) ? mTimeDiff : SystemClock.elapsedRealtime()
- mPlaybackStateCompat.getLastPositionUpdateTime();
long expectedPosition = mPlaybackStateCompat.getPosition()
+ (long) (mPlaybackStateCompat.getPlaybackSpeed() * timeDiff);
@@ -1208,6 +1234,15 @@
}
/**
+ * Sets the time diff forcefully when calculating current position.
+ * @param timeDiff {@code null} for reset.
+ */
+ @VisibleForTesting
+ void setTimeDiff(Long timeDiff) {
+ mTimeDiff = timeDiff;
+ }
+
+ /**
* Get the lastly cached playback speed from
* {@link ControllerCallback#onPlaybackSpeedChanged(MediaController2, float)}.
*
@@ -1684,11 +1719,16 @@
}
private void connectToService() {
- synchronized (mLock) {
- mBrowserCompat = new MediaBrowserCompat(mContext, mToken.getComponentName(),
- new ConnectionCallback(), sDefaultRootExtras);
- mBrowserCompat.connect();
- }
+ mCallbackExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mBrowserCompat = new MediaBrowserCompat(mContext, mToken.getComponentName(),
+ new ConnectionCallback(), sDefaultRootExtras);
+ mBrowserCompat.connect();
+ }
+ }
+ });
}
private void sendCommand(int commandCode) {
diff --git a/media/src/main/java/androidx/media/MediaLibraryService2.java b/media/src/main/java/androidx/media/MediaLibraryService2.java
index edd97c3..5a3a26c 100644
--- a/media/src/main/java/androidx/media/MediaLibraryService2.java
+++ b/media/src/main/java/androidx/media/MediaLibraryService2.java
@@ -23,8 +23,10 @@
import android.app.PendingIntent;
import android.content.Intent;
+import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
import androidx.annotation.NonNull;
@@ -36,7 +38,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
/**
@@ -291,7 +292,7 @@
*/
public void notifyChildrenChanged(@NonNull ControllerInfo controller,
@NonNull String parentId, int itemCount, @Nullable Bundle extras) {
- Bundle options = new Bundle(extras);
+ Bundle options = MediaUtils2.createBundle(extras);
options.putInt(MediaBrowser2.EXTRA_ITEM_COUNT, itemCount);
options.putBundle(MediaBrowser2.EXTRA_TARGET, controller.toBundle());
}
@@ -308,7 +309,7 @@
// This is for the backward compatibility.
public void notifyChildrenChanged(@NonNull String parentId, int itemCount,
@Nullable Bundle extras) {
- Bundle options = new Bundle(extras);
+ Bundle options = MediaUtils2.createBundle(extras);
options.putInt(MediaBrowser2.EXTRA_ITEM_COUNT, itemCount);
getServiceCompat().notifyChildrenChanged(parentId, options);
}
@@ -494,7 +495,6 @@
// controller.
return sDefaultBrowserRoot;
}
- final CountDownLatch latch = new CountDownLatch(1);
// TODO: Revisit this when we support caller information.
final ControllerInfo info = new ControllerInfo(MediaLibraryService2.this, clientUid, -1,
clientPackageName, null);
@@ -526,36 +526,47 @@
@Override
public void onLoadChildren(final String parentId, final Result<List<MediaItem>> result,
final Bundle options) {
+ result.detach();
final ControllerInfo controller = getController();
getLibrarySession().getCallbackExecutor().execute(new Runnable() {
@Override
public void run() {
- int page = options.getInt(EXTRA_PAGE, -1);
- int pageSize = options.getInt(EXTRA_PAGE_SIZE, -1);
- if (page >= 0 && pageSize >= 0) {
- // Requesting the list of children through the pagenation.
- List<MediaItem2> children = getLibrarySession().getCallback().onGetChildren(
- getLibrarySession(), controller, parentId, page, pageSize, options);
- if (children == null) {
- result.sendError(null);
- } else {
- List<MediaItem> list = new ArrayList<>();
- for (int i = 0; i < children.size(); i++) {
- list.add(MediaUtils2.createMediaItem(children.get(i)));
+ if (options != null) {
+ options.setClassLoader(MediaLibraryService2.this.getClassLoader());
+ try {
+ int page = options.getInt(EXTRA_PAGE, -1);
+ int pageSize = options.getInt(EXTRA_PAGE_SIZE, -1);
+ if (page >= 0 && pageSize >= 0) {
+ // Requesting the list of children through the pagenation.
+ List<MediaItem2> children = getLibrarySession().getCallback()
+ .onGetChildren(getLibrarySession(), controller, parentId,
+ page,
+ pageSize, options);
+ if (children == null) {
+ result.sendResult(null);
+ } else {
+ List<MediaItem> list = new ArrayList<>();
+ for (int i = 0; i < children.size(); i++) {
+ list.add(MediaUtils2.createMediaItem(children.get(i)));
+ }
+ result.sendResult(list);
+ }
+ return;
}
- result.sendResult(list);
+ } catch (BadParcelableException e) {
+ // pass-through.
}
- } else {
- // Only wants to register callbacks
- getLibrarySession().getCallback().onSubscribe(getLibrarySession(),
- controller, parentId, options);
}
+ // No valid pagination info. Only wants to register callbacks
+ getLibrarySession().getCallback().onSubscribe(getLibrarySession(),
+ controller, parentId, options);
}
});
}
@Override
public void onLoadItem(final String itemId, final Result<MediaItem> result) {
+ result.detach();
final ControllerInfo controller = getController();
getLibrarySession().getCallbackExecutor().execute(new Runnable() {
@Override
@@ -563,7 +574,7 @@
MediaItem2 item = getLibrarySession().getCallback().onGetItem(
getLibrarySession(), controller, itemId);
if (item == null) {
- result.sendError(null);
+ result.sendResult(null);
} else {
result.sendResult(MediaUtils2.createMediaItem(item));
}
@@ -583,7 +594,8 @@
private ControllerInfo getController() {
// TODO: Implement, by using getBrowserRootHints() / getCurrentBrowserInfo() / ...
- return null;
+ return new ControllerInfo(MediaLibraryService2.this, Process.myUid(), Process.myPid(),
+ getPackageName(), null);
}
}
}
diff --git a/media/src/main/java/androidx/media/MediaPlayer2.java b/media/src/main/java/androidx/media/MediaPlayer2.java
index 1864d72..f1cd3b6 100644
--- a/media/src/main/java/androidx/media/MediaPlayer2.java
+++ b/media/src/main/java/androidx/media/MediaPlayer2.java
@@ -28,6 +28,7 @@
import android.media.MediaTimestamp;
import android.media.PlaybackParams;
import android.media.ResourceBusyException;
+import android.media.SubtitleData;
import android.media.SyncParams;
import android.media.TimedMetaData;
import android.media.UnsupportedSchemeException;
@@ -47,7 +48,6 @@
import java.util.UUID;
import java.util.concurrent.Executor;
-
/**
* @hide
* MediaPlayer2 class can be used to control playback
@@ -832,10 +832,7 @@
*
* Additional vendor-specific fields may also be present in
* the return value.
- * @hide
- * TODO: This method is not ready for public. Currently returns metrics data in MediaPlayer1.
*/
- @RestrictTo(LIBRARY_GROUP)
public abstract PersistableBundle getMetrics();
/**
@@ -1229,13 +1226,26 @@
@CallStatus int status) { }
/**
- * Called to indicate media clock has changed.
+ * Called when a discontinuity in the normal progression of the media time is detected.
+ * The "normal progression" of media time is defined as the expected increase of the
+ * playback position when playing media, relative to the playback speed (for instance every
+ * second, media time increases by two seconds when playing at 2x).<br>
+ * Discontinuities are encountered in the following cases:
+ * <ul>
+ * <li>when the player is starved for data and cannot play anymore</li>
+ * <li>when the player encounters a playback error</li>
+ * <li>when the a seek operation starts, and when it's completed</li>
+ * <li>when the playback speed changes</li>
+ * <li>when the playback state changes</li>
+ * <li>when the player is reset</li>
+ * </ul>
*
* @param mp the MediaPlayer2 the media time pertains to.
* @param dsd the DataSourceDesc of this data source
- * @param timestamp the new media clock.
+ * @param timestamp the timestamp that correlates media time, system time and clock rate,
+ * or {@link MediaTimestamp#TIMESTAMP_UNKNOWN} in an error case.
*/
- public void onMediaTimeChanged(
+ public void onMediaTimeDiscontinuity(
MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { }
/**
@@ -1247,12 +1257,14 @@
*/
public void onCommandLabelReached(MediaPlayer2 mp, @NonNull Object label) { }
- /* TODO : uncomment below once API is available in supportlib.
+ /**
* Called when when a player subtitle track has new subtitle data available.
* @param mp the player that reports the new subtitle data
+ * @param dsd the DataSourceDesc of this data source
* @param data the subtitle data
*/
- // public void onSubtitleData(MediaPlayer2 mp, @NonNull SubtitleData data) { }
+ public void onSubtitleData(
+ MediaPlayer2 mp, DataSourceDesc dsd, @NonNull SubtitleData data) { }
}
/**
@@ -1512,16 +1524,6 @@
*/
public static final int CALL_COMPLETED_PREPARE = 6;
- /** The player just completed a call {@link #releaseDrm}.
- * @see MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
- */
- public static final int CALL_COMPLETED_RELEASE_DRM = 12;
-
- /** The player just completed a call {@link #restoreDrmKeys}.
- * @see MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
- */
- public static final int CALL_COMPLETED_RESTORE_DRM_KEYS = 13;
-
/** The player just completed a call {@link #seekTo}.
* @see MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
*/
@@ -1609,8 +1611,6 @@
CALL_COMPLETED_PAUSE,
CALL_COMPLETED_PLAY,
CALL_COMPLETED_PREPARE,
- CALL_COMPLETED_RELEASE_DRM,
- CALL_COMPLETED_RESTORE_DRM_KEYS,
CALL_COMPLETED_SEEK_TO,
CALL_COMPLETED_SELECT_TRACK,
CALL_COMPLETED_SET_AUDIO_ATTRIBUTES,
@@ -1661,12 +1661,6 @@
*/
public static final int CALL_STATUS_ERROR_IO = 4;
- /** Status code represents that DRM operation is called before preparing a DRM scheme through
- * {@link #prepareDrm}.
- * @see MediaPlayer2.MediaPlayer2EventCallback#onCallCompleted
- */
- public static final int CALL_STATUS_NO_DRM_SCHEME = 5;
-
/**
* @hide
*/
@@ -1676,8 +1670,7 @@
CALL_STATUS_INVALID_OPERATION,
CALL_STATUS_BAD_VALUE,
CALL_STATUS_PERMISSION_DENIED,
- CALL_STATUS_ERROR_IO,
- CALL_STATUS_NO_DRM_SCHEME})
+ CALL_STATUS_ERROR_IO})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(LIBRARY_GROUP)
public @interface CallStatus {}
@@ -2008,4 +2001,100 @@
super(detailMessage);
}
}
+
+ /**
+ * Definitions for the metrics that are reported via the {@link #getMetrics} call.
+ */
+ public static final class MetricsConstants {
+ private MetricsConstants() {}
+
+ /**
+ * Key to extract the MIME type of the video track
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
+
+ /**
+ * Key to extract the codec being used to decode the video track
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+
+ /**
+ * Key to extract the width (in pixels) of the video track
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String WIDTH = "android.media.mediaplayer.width";
+
+ /**
+ * Key to extract the height (in pixels) of the video track
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String HEIGHT = "android.media.mediaplayer.height";
+
+ /**
+ * Key to extract the count of video frames played
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String FRAMES = "android.media.mediaplayer.frames";
+
+ /**
+ * Key to extract the count of video frames dropped
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+
+ /**
+ * Key to extract the MIME type of the audio track
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
+
+ /**
+ * Key to extract the codec being used to decode the audio track
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+
+ /**
+ * Key to extract the duration (in milliseconds) of the
+ * media being played
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is a long.
+ */
+ public static final String DURATION = "android.media.mediaplayer.durationMs";
+
+ /**
+ * Key to extract the playing time (in milliseconds) of the
+ * media being played
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is a long.
+ */
+ public static final String PLAYING = "android.media.mediaplayer.playingMs";
+
+ /**
+ * Key to extract the count of errors encountered while
+ * playing the media
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String ERRORS = "android.media.mediaplayer.err";
+
+ /**
+ * Key to extract an (optional) error code detected while
+ * playing the media
+ * from the {@link MediaPlayer2#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
+
+ }
}
diff --git a/media/src/main/java/androidx/media/MediaPlayer2Impl.java b/media/src/main/java/androidx/media/MediaPlayer2Impl.java
index 3b3e119..d9338d3 100644
--- a/media/src/main/java/androidx/media/MediaPlayer2Impl.java
+++ b/media/src/main/java/androidx/media/MediaPlayer2Impl.java
@@ -28,6 +28,7 @@
import android.media.MediaTimestamp;
import android.media.PlaybackParams;
import android.media.ResourceBusyException;
+import android.media.SubtitleData;
import android.media.SyncParams;
import android.media.TimedMetaData;
import android.media.UnsupportedSchemeException;
@@ -70,13 +71,14 @@
private static final String TAG = "MediaPlayer2Impl";
- private static final int NEXT_SOURCE_STATE_ERROR = -1;
- private static final int NEXT_SOURCE_STATE_INIT = 0;
- private static final int NEXT_SOURCE_STATE_PREPARING = 1;
- private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+ private static final int SOURCE_STATE_ERROR = -1;
+ private static final int SOURCE_STATE_INIT = 0;
+ private static final int SOURCE_STATE_PREPARING = 1;
+ private static final int SOURCE_STATE_PREPARED = 2;
private static ArrayMap<Integer, Integer> sInfoEventMap;
private static ArrayMap<Integer, Integer> sErrorEventMap;
+ private static ArrayMap<Integer, Integer> sPrepareDrmStatusMap;
static {
sInfoEventMap = new ArrayMap<>();
@@ -106,24 +108,22 @@
sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_MALFORMED, MEDIA_ERROR_MALFORMED);
sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_UNSUPPORTED, MEDIA_ERROR_UNSUPPORTED);
sErrorEventMap.put(MediaPlayer.MEDIA_ERROR_TIMED_OUT, MEDIA_ERROR_TIMED_OUT);
+
+ sPrepareDrmStatusMap = new ArrayMap<>();
+ sPrepareDrmStatusMap.put(
+ MediaPlayer.PREPARE_DRM_STATUS_SUCCESS, PREPARE_DRM_STATUS_SUCCESS);
+ sPrepareDrmStatusMap.put(
+ MediaPlayer.PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR,
+ PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR);
+ sPrepareDrmStatusMap.put(
+ MediaPlayer.PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
+ PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR);
+ sPrepareDrmStatusMap.put(
+ MediaPlayer.PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
+ PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR);
}
- private MediaPlayer mPlayer; // MediaPlayer is thread-safe.
-
- private final Object mSrcLock = new Object();
- //--- guarded by |mSrcLock| start
- private long mSrcIdGenerator = 0;
- private DataSourceDesc mCurrentDSD;
- private long mCurrentSrcId = mSrcIdGenerator++;
- private List<DataSourceDesc> mNextDSDs;
- private long mNextSrcId = mSrcIdGenerator++;
- private int mNextSourceState = NEXT_SOURCE_STATE_INIT;
- private boolean mNextSourcePlayPending = false;
- //--- guarded by |mSrcLock| end
-
- private AtomicInteger mBufferedPercentageCurrent = new AtomicInteger(0);
- private AtomicInteger mBufferedPercentageNext = new AtomicInteger(0);
- private volatile float mVolume = 1.0f;
+ private MediaPlayerSourceQueue mPlayer;
private HandlerThread mHandlerThread;
private final Handler mTaskHandler;
@@ -135,8 +135,6 @@
private final Object mLock = new Object();
//--- guarded by |mLock| start
- @PlayerState private int mPlayerState;
- @BuffState private int mBufferingState;
private AudioAttributesCompat mAudioAttributes;
private ArrayList<Pair<Executor, MediaPlayer2EventCallback>> mMp2EventCallbackRecords =
new ArrayList<>();
@@ -146,6 +144,18 @@
new ArrayList<>();
//--- guarded by |mLock| end
+ private void handleDataSourceError(final DataSourceError err) {
+ if (err == null) {
+ return;
+ }
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback callback) {
+ callback.onError(MediaPlayer2Impl.this, err.mDSD, err.mWhat, err.mExtra);
+ }
+ });
+ }
+
/**
* Default constructor.
* <p>When done with the MediaPlayer2Impl, you should call {@link #close()},
@@ -157,10 +167,10 @@
mHandlerThread.start();
Looper looper = mHandlerThread.getLooper();
mTaskHandler = new Handler(looper);
- mPlayer = new MediaPlayer();
- mPlayerState = PLAYER_STATE_IDLE;
- mBufferingState = BUFFERING_STATE_UNKNOWN;
- setUpListeners();
+
+ // TODO: To make sure MediaPlayer1 listeners work, the caller thread should have a looper.
+ // Fix the framework or document this behavior.
+ mPlayer = new MediaPlayerSourceQueue();
}
/**
@@ -204,8 +214,7 @@
addTask(new Task(CALL_COMPLETED_PLAY, false) {
@Override
void process() {
- mPlayer.start();
- setPlayerState(PLAYER_STATE_PLAYING);
+ mPlayer.play();
}
});
}
@@ -226,7 +235,6 @@
@Override
void process() throws IOException {
mPlayer.prepareAsync();
- setBufferingState(BUFFERING_STATE_BUFFERING_AND_STARVED);
}
});
}
@@ -242,7 +250,6 @@
@Override
void process() {
mPlayer.pause();
- setPlayerState(PLAYER_STATE_PAUSED);
}
});
}
@@ -295,14 +302,12 @@
@Override
public long getBufferedPosition() {
// Use cached buffered percent for now.
- return getDuration() * mBufferedPercentageCurrent.get() / 100;
+ return mPlayer.getBufferedPosition();
}
@Override
public @PlayerState int getPlayerState() {
- synchronized (mLock) {
- return mPlayerState;
- }
+ return mPlayer.getPlayerState();
}
/**
@@ -312,9 +317,7 @@
*/
@Override
public @BuffState int getBufferingState() {
- synchronized (mLock) {
- return mBufferingState;
- }
+ return mPlayer.getBufferingState();
}
/**
@@ -361,13 +364,10 @@
void process() {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
// TODO: setDataSource could update exist data source
- synchronized (mSrcLock) {
- mCurrentDSD = dsd;
- mCurrentSrcId = mSrcIdGenerator++;
- try {
- handleDataSource(true /* isCurrent */, dsd, mCurrentSrcId);
- } catch (IOException e) {
- }
+ try {
+ mPlayer.setFirst(dsd);
+ } catch (IOException e) {
+ Log.e(TAG, "process: setDataSource", e);
}
}
});
@@ -387,21 +387,7 @@
@Override
void process() {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- synchronized (mSrcLock) {
- mNextDSDs = new ArrayList<DataSourceDesc>(1);
- mNextDSDs.add(dsd);
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
- mNextSourcePlayPending = false;
- }
- /* FIXME : define and handle state.
- int state = getMediaPlayer2State();
- if (state != MEDIAPLAYER2_STATE_IDLE) {
- synchronized (mSrcLock) {
- prepareNextDataSource_l();
- }
- }
- */
+ handleDataSourceError(mPlayer.setNext(dsd));
}
});
}
@@ -427,30 +413,14 @@
"DataSourceDesc in the source list cannot be null.");
}
}
-
- synchronized (mSrcLock) {
- mNextDSDs = new ArrayList(dsds);
- mNextSrcId = mSrcIdGenerator++;
- mNextSourceState = NEXT_SOURCE_STATE_INIT;
- mNextSourcePlayPending = false;
- }
- /* FIXME : define and handle state.
- int state = getMediaPlayer2State();
- if (state != MEDIAPLAYER2_STATE_IDLE) {
- synchronized (mSrcLock) {
- prepareNextDataSource_l();
- }
- }
- */
+ handleDataSourceError(mPlayer.setNextMultiple(dsds));
}
});
}
@Override
public @NonNull DataSourceDesc getCurrentDataSource() {
- synchronized (mSrcLock) {
- return mCurrentDSD;
- }
+ return mPlayer.getFirst().getDSD();
}
/**
@@ -521,8 +491,7 @@
addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
@Override
void process() {
- mVolume = volume;
- mPlayer.setVolume(volume, volume);
+ mPlayer.setVolume(volume);
}
});
}
@@ -534,7 +503,7 @@
*/
@Override
public float getPlayerVolume() {
- return mVolume;
+ return mPlayer.getVolume();
}
/**
@@ -650,14 +619,15 @@
}
}
- private void handleDataSource(boolean isCurrent, @NonNull final DataSourceDesc dsd, long srcId)
+ private static void handleDataSource(MediaPlayerSource src)
throws IOException {
+ final DataSourceDesc dsd = src.getDSD();
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- // TODO: handle the case isCurrent is false.
+ MediaPlayer player = src.mPlayer;
switch (dsd.getType()) {
case DataSourceDesc.TYPE_CALLBACK:
- mPlayer.setDataSource(new MediaDataSource() {
+ player.setDataSource(new MediaDataSource() {
Media2DataSource mDataSource = dsd.getMedia2DataSource();
@Override
public int readAt(long position, byte[] buffer, int offset, int size)
@@ -678,14 +648,14 @@
break;
case DataSourceDesc.TYPE_FD:
- mPlayer.setDataSource(
+ player.setDataSource(
dsd.getFileDescriptor(),
dsd.getFileDescriptorOffset(),
dsd.getFileDescriptorLength());
break;
case DataSourceDesc.TYPE_URI:
- mPlayer.setDataSource(
+ player.setDataSource(
dsd.getUriContext(),
dsd.getUri(),
dsd.getUriHeaders(),
@@ -871,9 +841,12 @@
@Override
public void reset() {
mPlayer.reset();
- setPlayerState(PLAYER_STATE_IDLE);
- setBufferingState(BUFFERING_STATE_UNKNOWN);
- /* FIXME: reset other internal variables. */
+ synchronized (mLock) {
+ mAudioAttributes = null;
+ mMp2EventCallbackRecords.clear();
+ mPlayerEventCallbackMap.clear();
+ mDrmEventCallbackRecords.clear();
+ }
}
/**
@@ -1230,8 +1203,9 @@
mPlayer.setOnDrmConfigHelper(new MediaPlayer.OnDrmConfigHelper() {
@Override
public void onDrmConfig(MediaPlayer mp) {
- /** FIXME: pass the right DSD. */
- listener.onDrmConfig(MediaPlayer2Impl.this, null);
+ MediaPlayerSource src = mPlayer.getSourceForPlayer(mp);
+ DataSourceDesc dsd = src == null ? null : src.getDSD();
+ listener.onDrmConfig(MediaPlayer2Impl.this, dsd);
}
});
}
@@ -1340,16 +1314,11 @@
*/
@Override
public void releaseDrm() throws NoDrmSchemeException {
- addTask(new Task(CALL_COMPLETED_RELEASE_DRM, false) {
- @Override
- void process() throws NoDrmSchemeException {
- try {
- mPlayer.releaseDrm();
- } catch (MediaPlayer.NoDrmSchemeException e) {
- throw new NoDrmSchemeException(e.getMessage());
- }
- }
- });
+ try {
+ mPlayer.releaseDrm();
+ } catch (MediaPlayer.NoDrmSchemeException e) {
+ throw new NoDrmSchemeException(e.getMessage());
+ }
}
@@ -1443,16 +1412,11 @@
@Override
public void restoreDrmKeys(@NonNull final byte[] keySetId)
throws NoDrmSchemeException {
- addTask(new Task(CALL_COMPLETED_RESTORE_DRM_KEYS, false) {
- @Override
- void process() throws NoDrmSchemeException {
- try {
- mPlayer.restoreKeys(keySetId);
- } catch (MediaPlayer.NoDrmSchemeException e) {
- throw new NoDrmSchemeException(e.getMessage());
- }
- }
- });
+ try {
+ mPlayer.restoreKeys(keySetId);
+ } catch (MediaPlayer.NoDrmSchemeException e) {
+ throw new NoDrmSchemeException(e.getMessage());
+ }
}
@@ -1504,7 +1468,7 @@
private void setPlaybackParamsInternal(final PlaybackParams params) {
PlaybackParams current = mPlayer.getPlaybackParams();
mPlayer.setPlaybackParams(params);
- if (Math.abs(current.getSpeed() - params.getSpeed()) > 0.0001f) {
+ if (current.getSpeed() != params.getSpeed()) {
notifyPlayerEvent(new PlayerEventNotifier() {
@Override
public void notify(PlayerEventCallback cb) {
@@ -1514,36 +1478,6 @@
}
}
- private void setPlayerState(@PlayerState final int state) {
- synchronized (mLock) {
- if (mPlayerState == state) {
- return;
- }
- mPlayerState = state;
- }
- notifyPlayerEvent(new PlayerEventNotifier() {
- @Override
- public void notify(PlayerEventCallback cb) {
- cb.onPlayerStateChanged(MediaPlayer2Impl.this, state);
- }
- });
- }
-
- private void setBufferingState(@BuffState final int state) {
- synchronized (mLock) {
- if (mBufferingState == state) {
- return;
- }
- mBufferingState = state;
- }
- notifyPlayerEvent(new PlayerEventNotifier() {
- @Override
- public void notify(PlayerEventCallback cb) {
- cb.onBufferingStateChanged(MediaPlayer2Impl.this, mCurrentDSD, state);
- }
- });
- }
-
private void notifyMediaPlayer2Event(final Mp2EventNotifier notifier) {
List<Pair<Executor, MediaPlayer2EventCallback>> records;
synchronized (mLock) {
@@ -1577,6 +1511,21 @@
}
}
+ private void notifyDrmEvent(final DrmEventNotifier notifier) {
+ List<Pair<Executor, DrmEventCallback>> records;
+ synchronized (mLock) {
+ records = new ArrayList<>(mDrmEventCallbackRecords);
+ }
+ for (final Pair<Executor, DrmEventCallback> record : records) {
+ record.first.execute(new Runnable() {
+ @Override
+ public void run() {
+ notifier.notify(record.second);
+ }
+ });
+ }
+ }
+
private interface Mp2EventNotifier {
void notify(MediaPlayer2EventCallback callback);
}
@@ -1585,28 +1534,34 @@
void notify(PlayerEventCallback callback);
}
- private void setUpListeners() {
- mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ private interface DrmEventNotifier {
+ void notify(DrmEventCallback callback);
+ }
+
+ private void setUpListeners(final MediaPlayerSource src) {
+ MediaPlayer p = src.mPlayer;
+ p.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
- setPlayerState(PLAYER_STATE_PAUSED);
- setBufferingState(BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+ handleDataSourceError(mPlayer.onPrepared(mp));
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback callback) {
- callback.onInfo(MediaPlayer2Impl.this, mCurrentDSD, MEDIA_INFO_PREPARED, 0);
+ MediaPlayer2Impl mp2 = MediaPlayer2Impl.this;
+ DataSourceDesc dsd = src.getDSD();
+ callback.onInfo(mp2, dsd, MEDIA_INFO_PREPARED, 0);
}
});
notifyPlayerEvent(new PlayerEventNotifier() {
@Override
public void notify(PlayerEventCallback cb) {
- cb.onMediaPrepared(MediaPlayer2Impl.this, mCurrentDSD);
+ cb.onMediaPrepared(MediaPlayer2Impl.this, src.getDSD());
}
});
synchronized (mTaskLock) {
if (mCurrentTask != null
&& mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
- && mCurrentTask.mDSD == mCurrentDSD
+ && mCurrentTask.mDSD == src.getDSD()
&& mCurrentTask.mNeedToWaitForEventToComplete) {
mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
mCurrentTask = null;
@@ -1615,18 +1570,18 @@
}
}
});
- mPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
+ p.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, final int width, final int height) {
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback cb) {
- cb.onVideoSizeChanged(MediaPlayer2Impl.this, mCurrentDSD, width, height);
+ cb.onVideoSizeChanged(MediaPlayer2Impl.this, src.getDSD(), width, height);
}
});
}
});
- mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
+ p.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch (what) {
@@ -1634,50 +1589,50 @@
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback cb) {
- cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
+ cb.onInfo(MediaPlayer2Impl.this, src.getDSD(),
MEDIA_INFO_VIDEO_RENDERING_START, 0);
}
});
break;
case MediaPlayer.MEDIA_INFO_BUFFERING_START:
- setBufferingState(BUFFERING_STATE_BUFFERING_AND_STARVED);
+ mPlayer.setBufferingState(mp, BUFFERING_STATE_BUFFERING_AND_STARVED);
break;
case MediaPlayer.MEDIA_INFO_BUFFERING_END:
- setBufferingState(BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+ mPlayer.setBufferingState(mp, BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
break;
}
return false;
}
});
- mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ p.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
- setPlayerState(PLAYER_STATE_PAUSED);
+ handleDataSourceError(mPlayer.onCompletion(mp));
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback cb) {
- cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD, MEDIA_INFO_PLAYBACK_COMPLETE,
- 0);
+ MediaPlayer2Impl mp2 = MediaPlayer2Impl.this;
+ DataSourceDesc dsd = src.getDSD();
+ cb.onInfo(mp2, dsd, MEDIA_INFO_PLAYBACK_COMPLETE, 0);
}
});
}
});
- mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ p.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, final int what, final int extra) {
- setPlayerState(PLAYER_STATE_ERROR);
- setBufferingState(BUFFERING_STATE_UNKNOWN);
+ mPlayer.onError(mp);
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback cb) {
int w = sErrorEventMap.getOrDefault(what, MEDIA_ERROR_UNKNOWN);
- cb.onError(MediaPlayer2Impl.this, mCurrentDSD, w, extra);
+ cb.onError(MediaPlayer2Impl.this, src.getDSD(), w, extra);
}
});
return true;
}
});
- mPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
+ p.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
synchronized (mTaskLock) {
@@ -1700,7 +1655,7 @@
});
}
});
- mPlayer.setOnTimedMetaDataAvailableListener(
+ p.setOnTimedMetaDataAvailableListener(
new MediaPlayer.OnTimedMetaDataAvailableListener() {
@Override
public void onTimedMetaDataAvailable(MediaPlayer mp, final TimedMetaData data) {
@@ -1708,40 +1663,90 @@
@Override
public void notify(MediaPlayer2EventCallback cb) {
cb.onTimedMetaDataAvailable(
- MediaPlayer2Impl.this, mCurrentDSD, data);
+ MediaPlayer2Impl.this, src.getDSD(), data);
}
});
}
});
- mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
+ p.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, final int what, final int extra) {
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback cb) {
int w = sInfoEventMap.getOrDefault(what, MEDIA_INFO_UNKNOWN);
- cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD, w, extra);
+ cb.onInfo(MediaPlayer2Impl.this, src.getDSD(), w, extra);
}
});
return true;
}
});
- mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
+ p.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, final int percent) {
if (percent >= 100) {
- setBufferingState(BUFFERING_STATE_BUFFERING_COMPLETE);
+ mPlayer.setBufferingState(mp, BUFFERING_STATE_BUFFERING_COMPLETE);
}
- mBufferedPercentageCurrent.set(percent);
+ src.mBufferedPercentage.set(percent);
notifyMediaPlayer2Event(new Mp2EventNotifier() {
@Override
public void notify(MediaPlayer2EventCallback cb) {
- cb.onInfo(MediaPlayer2Impl.this, mCurrentDSD,
+ cb.onInfo(MediaPlayer2Impl.this, src.getDSD(),
MEDIA_INFO_BUFFERING_UPDATE, percent);
}
});
}
});
+ p.setOnMediaTimeDiscontinuityListener(
+ new MediaPlayer.OnMediaTimeDiscontinuityListener() {
+ @Override
+ public void onMediaTimeDiscontinuity(
+ MediaPlayer mp, final MediaTimestamp timestamp) {
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onMediaTimeDiscontinuity(
+ MediaPlayer2Impl.this, src.getDSD(), timestamp);
+ }
+ });
+ }
+ });
+ p.setOnSubtitleDataListener(new MediaPlayer.OnSubtitleDataListener() {
+ @Override
+ public void onSubtitleData(MediaPlayer mp, final SubtitleData data) {
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback cb) {
+ cb.onSubtitleData(MediaPlayer2Impl.this, src.getDSD(), data);
+ }
+ });
+ }
+ });
+ p.setOnDrmInfoListener(new MediaPlayer.OnDrmInfoListener() {
+ @Override
+ public void onDrmInfo(MediaPlayer mp, final MediaPlayer.DrmInfo drmInfo) {
+ notifyDrmEvent(new DrmEventNotifier() {
+ @Override
+ public void notify(DrmEventCallback cb) {
+ cb.onDrmInfo(MediaPlayer2Impl.this, src.getDSD(),
+ new DrmInfoImpl(drmInfo.getPssh(), drmInfo.getSupportedSchemes()));
+ }
+ });
+ }
+ });
+ p.setOnDrmPreparedListener(new MediaPlayer.OnDrmPreparedListener() {
+ @Override
+ public void onDrmPrepared(MediaPlayer mp, final int status) {
+ notifyDrmEvent(new DrmEventNotifier() {
+ @Override
+ public void notify(DrmEventCallback cb) {
+ int s = sPrepareDrmStatusMap.getOrDefault(
+ status, PREPARE_DRM_STATUS_PREPARATION_ERROR);
+ cb.onDrmPrepared(MediaPlayer2Impl.this, src.getDSD(), s);
+ }
+ });
+ }
+ });
}
/**
@@ -1944,14 +1949,10 @@
status = CALL_STATUS_PERMISSION_DENIED;
} catch (IOException e) {
status = CALL_STATUS_ERROR_IO;
- } catch (NoDrmSchemeException e) {
- status = CALL_STATUS_NO_DRM_SCHEME;
} catch (Exception e) {
status = CALL_STATUS_ERROR_UNKNOWN;
}
- synchronized (mSrcLock) {
- mDSD = mCurrentDSD;
- }
+ mDSD = getCurrentDataSource();
if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
@@ -1979,4 +1980,427 @@
});
}
};
+
+ private static class DataSourceError {
+ final DataSourceDesc mDSD;
+ final int mWhat;
+
+ final int mExtra;
+ DataSourceError(DataSourceDesc dsd, int what, int extra) {
+ mDSD = dsd;
+ mWhat = what;
+ mExtra = extra;
+ }
+
+ }
+
+ private class MediaPlayerSource {
+
+ volatile DataSourceDesc mDSD;
+ final MediaPlayer mPlayer = new MediaPlayer();
+ final AtomicInteger mBufferedPercentage = new AtomicInteger(0);
+ int mSourceState = SOURCE_STATE_INIT;
+ @BuffState int mBufferingState = BUFFERING_STATE_UNKNOWN;
+ @PlayerState int mPlayerState = PLAYER_STATE_IDLE;
+ boolean mPlayPending;
+
+ MediaPlayerSource(final DataSourceDesc dsd) {
+ mDSD = dsd;
+ setUpListeners(this);
+ }
+
+ DataSourceDesc getDSD() {
+ return mDSD;
+ }
+
+ }
+
+ private class MediaPlayerSourceQueue {
+
+ List<MediaPlayerSource> mQueue = new ArrayList<>();
+ float mVolume = 1.0f;
+ Surface mSurface;
+
+ MediaPlayerSourceQueue() {
+ mQueue.add(new MediaPlayerSource(null));
+ }
+
+ synchronized MediaPlayer getCurrentPlayer() {
+ return mQueue.get(0).mPlayer;
+ }
+
+ synchronized MediaPlayerSource getFirst() {
+ return mQueue.get(0);
+ }
+
+ synchronized void setFirst(DataSourceDesc dsd) throws IOException {
+ if (mQueue.isEmpty()) {
+ mQueue.add(0, new MediaPlayerSource(dsd));
+ } else {
+ mQueue.get(0).mDSD = dsd;
+ setUpListeners(mQueue.get(0));
+ }
+ handleDataSource(mQueue.get(0));
+ }
+
+ synchronized DataSourceError setNext(DataSourceDesc dsd) {
+ MediaPlayerSource src = new MediaPlayerSource(dsd);
+ if (mQueue.isEmpty()) {
+ mQueue.add(src);
+ return prepareMediaPlayerSource(0);
+ } else {
+ mQueue.add(1, src);
+ return prepareMediaPlayerSource(1);
+ }
+ }
+
+ synchronized DataSourceError setNextMultiple(List<DataSourceDesc> descs) {
+ List<MediaPlayerSource> sources = new ArrayList<>();
+ for (DataSourceDesc dsd: descs) {
+ sources.add(new MediaPlayerSource(dsd));
+ }
+ if (mQueue.isEmpty()) {
+ mQueue.addAll(sources);
+ return prepareMediaPlayerSource(0);
+ } else {
+ mQueue.addAll(1, sources);
+ return prepareMediaPlayerSource(1);
+ }
+ }
+
+ synchronized void play() {
+ MediaPlayerSource src = mQueue.get(0);
+ if (src.mSourceState == SOURCE_STATE_PREPARED) {
+ src.mPlayer.start();
+ setPlayerState(src.mPlayer, PLAYER_STATE_PLAYING);
+ }
+ }
+
+ synchronized void prepare() {
+ getCurrentPlayer().prepareAsync();
+ }
+
+ synchronized void release() {
+ getCurrentPlayer().release();
+ }
+
+ synchronized void prepareAsync() {
+ MediaPlayer mp = getCurrentPlayer();
+ mp.prepareAsync();
+ setBufferingState(mp, BUFFERING_STATE_BUFFERING_AND_STARVED);
+ }
+
+ synchronized void pause() {
+ MediaPlayer mp = getCurrentPlayer();
+ mp.pause();
+ setPlayerState(mp, PLAYER_STATE_PAUSED);
+ }
+
+ synchronized long getCurrentPosition() {
+ return getCurrentPlayer().getCurrentPosition();
+ }
+
+ synchronized long getDuration() {
+ return getCurrentPlayer().getDuration();
+ }
+
+ synchronized long getBufferedPosition() {
+ MediaPlayerSource src = mQueue.get(0);
+ return (long) src.mPlayer.getDuration() * src.mBufferedPercentage.get() / 100;
+ }
+
+ synchronized void setAudioAttributes(AudioAttributes attributes) {
+ getCurrentPlayer().setAudioAttributes(attributes);
+ }
+
+ synchronized DataSourceError onPrepared(MediaPlayer mp) {
+ for (int i = 0; i < mQueue.size(); i++) {
+ MediaPlayerSource src = mQueue.get(i);
+ if (mp == src.mPlayer) {
+ if (i == 0) {
+ if (src.mPlayPending) {
+ src.mPlayPending = false;
+ src.mPlayer.start();
+ setPlayerState(src.mPlayer, PLAYER_STATE_PLAYING);
+ } else {
+ setPlayerState(src.mPlayer, PLAYER_STATE_PAUSED);
+ }
+ }
+ src.mSourceState = SOURCE_STATE_PREPARED;
+ setBufferingState(src.mPlayer, BUFFERING_STATE_BUFFERING_AND_PLAYABLE);
+ return prepareMediaPlayerSource(i + 1);
+ }
+ }
+ return null;
+ }
+
+ synchronized DataSourceError onCompletion(MediaPlayer mp) {
+ if (!mQueue.isEmpty() && mp == getCurrentPlayer()) {
+ if (mQueue.size() == 1) {
+ setPlayerState(mp, PLAYER_STATE_PAUSED);
+ return null;
+ }
+ mp.release();
+ final MediaPlayerSource src1 = mQueue.remove(0);
+ final MediaPlayerSource src2 = mQueue.get(0);
+ if (src1.mPlayerState != src2.mPlayerState) {
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ cb.onPlayerStateChanged(MediaPlayer2Impl.this, src2.mPlayerState);
+ }
+ });
+ }
+
+ }
+
+ DataSourceError err = null;
+ final MediaPlayerSource src = mQueue.get(0);
+ src.mPlayer.setSurface(mSurface);
+ src.mPlayer.setVolume(mVolume, mVolume);
+ if (src.mSourceState == SOURCE_STATE_PREPARED) {
+ // start next source only when it's in prepared state.
+ src.mPlayer.start();
+ notifyMediaPlayer2Event(new Mp2EventNotifier() {
+ @Override
+ public void notify(MediaPlayer2EventCallback callback) {
+ callback.onInfo(MediaPlayer2Impl.this, src.getDSD(),
+ MEDIA_INFO_STARTED_AS_NEXT, 0);
+ }
+ });
+
+ } else {
+ if (src.mSourceState == SOURCE_STATE_INIT) {
+ err = prepareMediaPlayerSource(0);
+ }
+ src.mPlayPending = true;
+ }
+ return err;
+ }
+
+ synchronized void onError(MediaPlayer mp) {
+ setPlayerState(mp, PLAYER_STATE_ERROR);
+ setBufferingState(mp, BUFFERING_STATE_UNKNOWN);
+ }
+
+ synchronized DataSourceError prepareMediaPlayerSource(int n) {
+ if (n >= mQueue.size()
+ || mQueue.get(n).mSourceState != SOURCE_STATE_INIT
+ || getPlayerState() == PLAYER_STATE_IDLE) {
+ // There is no next source or it's in preparing or prepared state.
+ return null;
+ }
+
+ MediaPlayerSource src = mQueue.get(n);
+ try {
+ src.mSourceState = SOURCE_STATE_PREPARING;
+ handleDataSource(src);
+ src.mPlayer.prepareAsync();
+ return null;
+ } catch (Exception e) {
+ DataSourceDesc dsd = src.getDSD();
+ setPlayerState(src.mPlayer, PLAYER_STATE_ERROR);
+ return new DataSourceError(dsd, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED);
+ }
+
+ }
+
+ synchronized void setLooping(boolean loop) {
+ getCurrentPlayer().setLooping(loop);
+ }
+
+ synchronized void setPlaybackParams(PlaybackParams playbackParams) {
+ getCurrentPlayer().setPlaybackParams(playbackParams);
+ }
+
+ synchronized float getVolume() {
+ return mVolume;
+ }
+
+ synchronized void setVolume(float volume) {
+ mVolume = volume;
+ getCurrentPlayer().setVolume(volume, volume);
+ }
+
+ synchronized void setSurface(Surface surface) {
+ mSurface = surface;
+ getCurrentPlayer().setSurface(surface);
+ }
+
+ synchronized int getVideoWidth() {
+ return getCurrentPlayer().getVideoWidth();
+ }
+
+ synchronized int getVideoHeight() {
+ return getCurrentPlayer().getVideoHeight();
+ }
+
+ synchronized PersistableBundle getMetrics() {
+ return getCurrentPlayer().getMetrics();
+ }
+
+ synchronized PlaybackParams getPlaybackParams() {
+ return getCurrentPlayer().getPlaybackParams();
+ }
+
+ synchronized void setSyncParams(SyncParams params) {
+ getCurrentPlayer().setSyncParams(params);
+ }
+
+ synchronized SyncParams getSyncParams() {
+ return getCurrentPlayer().getSyncParams();
+ }
+
+ synchronized void seekTo(long msec, int mode) {
+ getCurrentPlayer().seekTo(msec, mode);
+ }
+
+ synchronized void reset() {
+ MediaPlayerSource src = mQueue.get(0);
+ src.mPlayer.reset();
+ src.mBufferedPercentage.set(0);
+ mVolume = 1.0f;
+ setPlayerState(src.mPlayer, PLAYER_STATE_IDLE);
+ setBufferingState(src.mPlayer, BUFFERING_STATE_UNKNOWN);
+ }
+
+ synchronized MediaTimestamp getTimestamp() {
+ return getCurrentPlayer().getTimestamp();
+ }
+
+ synchronized void setAudioSessionId(int sessionId) {
+ getCurrentPlayer().setAudioSessionId(sessionId);
+ }
+
+ synchronized int getAudioSessionId() {
+ return getCurrentPlayer().getAudioSessionId();
+ }
+
+ synchronized void attachAuxEffect(int effectId) {
+ getCurrentPlayer().attachAuxEffect(effectId);
+ }
+
+ synchronized void setAuxEffectSendLevel(float level) {
+ getCurrentPlayer().setAuxEffectSendLevel(level);
+ }
+
+ synchronized MediaPlayer.TrackInfo[] getTrackInfo() {
+ return getCurrentPlayer().getTrackInfo();
+ }
+
+ synchronized int getSelectedTrack(int trackType) {
+ return getCurrentPlayer().getSelectedTrack(trackType);
+ }
+
+ synchronized void selectTrack(int index) {
+ getCurrentPlayer().selectTrack(index);
+ }
+
+ synchronized void deselectTrack(int index) {
+ getCurrentPlayer().deselectTrack(index);
+ }
+
+ synchronized MediaPlayer.DrmInfo getDrmInfo() {
+ return getCurrentPlayer().getDrmInfo();
+ }
+
+ synchronized void prepareDrm(UUID uuid)
+ throws ResourceBusyException, MediaPlayer.ProvisioningServerErrorException,
+ MediaPlayer.ProvisioningNetworkErrorException, UnsupportedSchemeException {
+ getCurrentPlayer().prepareDrm(uuid);
+ }
+
+ synchronized void releaseDrm() throws MediaPlayer.NoDrmSchemeException {
+ getCurrentPlayer().releaseDrm();
+ }
+
+ synchronized byte[] provideKeyResponse(byte[] keySetId, byte[] response)
+ throws DeniedByServerException, MediaPlayer.NoDrmSchemeException {
+ return getCurrentPlayer().provideKeyResponse(keySetId, response);
+ }
+
+ synchronized void restoreKeys(byte[] keySetId) throws MediaPlayer.NoDrmSchemeException {
+ getCurrentPlayer().restoreKeys(keySetId);
+ }
+
+ synchronized String getDrmPropertyString(String propertyName)
+ throws MediaPlayer.NoDrmSchemeException {
+ return getCurrentPlayer().getDrmPropertyString(propertyName);
+ }
+
+ synchronized void setDrmPropertyString(String propertyName, String value)
+ throws MediaPlayer.NoDrmSchemeException {
+ getCurrentPlayer().setDrmPropertyString(propertyName, value);
+ }
+
+ synchronized void setOnDrmConfigHelper(MediaPlayer.OnDrmConfigHelper onDrmConfigHelper) {
+ getCurrentPlayer().setOnDrmConfigHelper(onDrmConfigHelper);
+ }
+
+ synchronized MediaDrm.KeyRequest getKeyRequest(byte[] keySetId, byte[] initData,
+ String mimeType,
+ int keyType, Map<String, String> optionalParameters)
+ throws MediaPlayer.NoDrmSchemeException {
+ return getCurrentPlayer().getKeyRequest(keySetId, initData, mimeType, keyType,
+ optionalParameters);
+ }
+
+ synchronized void setPlayerState(MediaPlayer mp, @PlayerState final int state) {
+ for (final MediaPlayerSource src: mQueue) {
+ if (src.mPlayer != mp) {
+ continue;
+ }
+ if (src.mPlayerState == state) {
+ return;
+ }
+ src.mPlayerState = state;
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ cb.onPlayerStateChanged(MediaPlayer2Impl.this, state);
+ }
+ });
+ return;
+ }
+ }
+
+ synchronized void setBufferingState(MediaPlayer mp, @BuffState final int state) {
+ for (final MediaPlayerSource src: mQueue) {
+ if (src.mPlayer != mp) {
+ continue;
+ }
+ if (src.mBufferingState == state) {
+ return;
+ }
+ src.mBufferingState = state;
+ notifyPlayerEvent(new PlayerEventNotifier() {
+ @Override
+ public void notify(PlayerEventCallback cb) {
+ MediaPlayer2Impl mp2 = MediaPlayer2Impl.this;
+ DataSourceDesc dsd = src.getDSD();
+ cb.onBufferingStateChanged(mp2, dsd, state);
+ }
+ });
+ return;
+ }
+ }
+
+ synchronized @BuffState int getBufferingState() {
+ return mQueue.get(0).mBufferingState;
+ }
+
+ synchronized @PlayerState int getPlayerState() {
+ return mQueue.get(0).mPlayerState;
+ }
+
+ synchronized MediaPlayerSource getSourceForPlayer(MediaPlayer mp) {
+ for (MediaPlayerSource src: mQueue) {
+ if (src.mPlayer == mp) {
+ return src;
+ }
+ }
+ return null;
+ }
+ }
+
}
diff --git a/media/src/main/java/androidx/media/MediaSession2ImplBase.java b/media/src/main/java/androidx/media/MediaSession2ImplBase.java
index e474b45..fc598f1 100644
--- a/media/src/main/java/androidx/media/MediaSession2ImplBase.java
+++ b/media/src/main/java/androidx/media/MediaSession2ImplBase.java
@@ -90,8 +90,6 @@
@GuardedBy("mLock")
private OnDataSourceMissingHelper mDsmHelper;
@GuardedBy("mLock")
- private PlaybackStateCompat mPlaybackStateCompat;
- @GuardedBy("mLock")
private PlaybackInfo mPlaybackInfo;
MediaSession2ImplBase(Context context, MediaSessionCompat sessionCompat, String id,
@@ -1047,6 +1045,21 @@
});
}
+ @Override
+ public void onSeekCompleted(final MediaPlayerBase mpb, final long position) {
+ final MediaSession2ImplBase session = getSession();
+ if (session == null) {
+ return;
+ }
+ session.getCallbackExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ session.getCallback().onSeekCompleted(session.getInstance(), mpb, position);
+ session.getSession2Stub().notifySeekCompleted(position);
+ }
+ });
+ }
+
private MediaSession2ImplBase getSession() {
final MediaSession2ImplBase session = mSession.get();
if (session == null && DEBUG) {
diff --git a/media/src/main/java/androidx/media/MediaSession2StubImplBase.java b/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
index 48e641e..1300698 100644
--- a/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
+++ b/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
@@ -55,7 +55,7 @@
import static androidx.media.MediaConstants2.CONTROLLER_COMMAND_CONNECT;
import static androidx.media.MediaConstants2.CONTROLLER_COMMAND_DISCONNECT;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED;
-import static androidx.media.MediaConstants2.SESSION_EVENT_ON_BUFFERING_STATE_CHAGNED;
+import static androidx.media.MediaConstants2.SESSION_EVENT_ON_BUFFERING_STATE_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_CURRENT_MEDIA_ITEM_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ERROR;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED;
@@ -65,6 +65,7 @@
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYLIST_METADATA_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_REPEAT_MODE_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ROUTES_INFO_CHANGED;
+import static androidx.media.MediaConstants2.SESSION_EVENT_ON_SEEK_COMPLETED;
import static androidx.media.MediaConstants2.SESSION_EVENT_ON_SHUFFLE_MODE_CHANGED;
import static androidx.media.MediaConstants2.SESSION_EVENT_SEND_CUSTOM_COMMAND;
import static androidx.media.MediaConstants2.SESSION_EVENT_SET_CUSTOM_LAYOUT;
@@ -561,6 +562,8 @@
public void run(ControllerInfo controller) throws RemoteException {
Bundle bundle = new Bundle();
bundle.putInt(ARGUMENT_PLAYER_STATE, state);
+ bundle.putParcelable(
+ ARGUMENT_PLAYBACK_STATE_COMPAT, mSession.getPlaybackStateCompat());
controller.getControllerBinder().onEvent(
SESSION_EVENT_ON_PLAYER_STATE_CHANGED, bundle);
}
@@ -587,8 +590,23 @@
Bundle bundle = new Bundle();
bundle.putBundle(ARGUMENT_MEDIA_ITEM, item.toBundle());
bundle.putInt(ARGUMENT_BUFFERING_STATE, bufferingState);
+ bundle.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
+ mSession.getPlaybackStateCompat());
controller.getControllerBinder().onEvent(
- SESSION_EVENT_ON_BUFFERING_STATE_CHAGNED, bundle);
+ SESSION_EVENT_ON_BUFFERING_STATE_CHANGED, bundle);
+ }
+ });
+ }
+
+ void notifySeekCompleted(final long position) {
+ notifyAll(new Session2Runnable() {
+ @Override
+ public void run(ControllerInfo controller) throws RemoteException {
+ Bundle bundle = new Bundle();
+ bundle.putLong(ARGUMENT_SEEK_POSITION, position);
+ bundle.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
+ mSession.getPlaybackStateCompat());
+ controller.getControllerBinder().onEvent(SESSION_EVENT_ON_SEEK_COMPLETED, bundle);
}
});
}
diff --git a/media/src/main/java/androidx/media/MediaSessionManager.java b/media/src/main/java/androidx/media/MediaSessionManager.java
new file mode 100644
index 0000000..43fe097
--- /dev/null
+++ b/media/src/main/java/androidx/media/MediaSessionManager.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.os.BuildCompat;
+
+/**
+ * @hide
+ * Provides support for interacting with {@link MediaSessionCompat media sessions} that
+ * applications have published to express their ongoing media playback state.
+ *
+ * @see MediaSessionCompat
+ * @see MediaControllerCompat
+ */
+@RestrictTo(LIBRARY_GROUP)
+public final class MediaSessionManager {
+ static final String TAG = "MediaSessionManager";
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static MediaSessionManager sSessionManager;
+
+ MediaSessionManagerImpl mImpl;
+
+ /**
+ * Gets an instance of the media session manager associated with the context.
+ *
+ * @return The MediaSessionManager instance for this context.
+ */
+ public static synchronized MediaSessionManager getSessionManager(Context context) {
+ if (sSessionManager == null) {
+ sSessionManager = new MediaSessionManager(context.getApplicationContext());
+ }
+ return sSessionManager;
+ }
+
+ private MediaSessionManager(Context context) {
+ if (BuildCompat.isAtLeastP()) {
+ mImpl = new MediaSessionManagerImplApi28(context);
+ } else if (Build.VERSION.SDK_INT >= 21) {
+ mImpl = new MediaSessionManagerImplApi21(context);
+ } else {
+ mImpl = new MediaSessionManagerImplBase(context);
+ }
+ }
+
+ /**
+ * Checks whether the remote user is a trusted app.
+ * <p>
+ * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+ * permission or has an enabled notification listener.
+ *
+ * @param userInfo The remote user info from either
+ * {@link MediaSessionCompat#getCurrentControllerInfo()} and
+ * {@link MediaBrowserServiceCompat#getCurrentBrowserInfo()}.
+ * @return {@code true} if the remote user is trusted and its package name matches with the UID.
+ * {@code false} otherwise.
+ */
+ public boolean isTrustedForMediaControl(@NonNull RemoteUserInfo userInfo) {
+ if (userInfo == null) {
+ throw new IllegalArgumentException("userInfo should not be null");
+ }
+ return mImpl.isTrustedForMediaControl(userInfo.mImpl);
+ }
+
+ Context getContext() {
+ return mImpl.getContext();
+ }
+
+ interface MediaSessionManagerImpl {
+ Context getContext();
+ boolean isTrustedForMediaControl(RemoteUserInfoImpl userInfo);
+ }
+
+ interface RemoteUserInfoImpl {
+ String getPackageName();
+ int getPid();
+ int getUid();
+ }
+
+ /**
+ * Information of a remote user of {@link android.support.v4.media.session.MediaSessionCompat}
+ * or {@link MediaBrowserServiceCompat}.
+ * This can be used to decide whether the remote user is trusted app.
+ *
+ * @see #isTrustedForMediaControl(RemoteUserInfo)
+ */
+ public static final class RemoteUserInfo {
+ /**
+ * Used by {@link #getPackageName()} when the session is connected to the legacy controller
+ * whose exact package name cannot be obtained.
+ */
+ public static String LEGACY_CONTROLLER = "android.media.session.MediaController";
+
+ RemoteUserInfoImpl mImpl;
+
+ public RemoteUserInfo(String packageName, int pid, int uid) {
+ if (BuildCompat.isAtLeastP()) {
+ mImpl = new MediaSessionManagerImplApi28.RemoteUserInfo(packageName, pid, uid);
+ } else {
+ mImpl = new MediaSessionManagerImplBase.RemoteUserInfo(packageName, pid, uid);
+ }
+ }
+
+ /**
+ * @return package name of the controller. Can be {@link #LEGACY_CONTROLLER} if the package
+ * name cannot be obtained.
+ */
+ public String getPackageName() {
+ return mImpl.getPackageName();
+ }
+
+ /**
+ * @return pid of the controller
+ */
+ public int getPid() {
+ return mImpl.getPid();
+ }
+
+ /**
+ * @return uid of the controller
+ */
+ public int getUid() {
+ return mImpl.getUid();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return mImpl.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return mImpl.hashCode();
+ }
+ }
+}
diff --git a/media/src/main/java/androidx/media/MediaSessionManagerImplApi21.java b/media/src/main/java/androidx/media/MediaSessionManagerImplApi21.java
new file mode 100644
index 0000000..4fefe70
--- /dev/null
+++ b/media/src/main/java/androidx/media/MediaSessionManagerImplApi21.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+@RequiresApi(21)
+class MediaSessionManagerImplApi21 extends MediaSessionManagerImplBase {
+ MediaSessionManagerImplApi21(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public boolean isTrustedForMediaControl(
+ @NonNull MediaSessionManager.RemoteUserInfoImpl userInfo) {
+
+ return hasMediaControlPermission(userInfo) || super.isTrustedForMediaControl(userInfo);
+ }
+
+ /**
+ * Checks the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL permission.
+ */
+ private boolean hasMediaControlPermission(
+ @NonNull MediaSessionManager.RemoteUserInfoImpl userInfo) {
+ return getContext().checkPermission(
+ android.Manifest.permission.MEDIA_CONTENT_CONTROL,
+ userInfo.getPid(), userInfo.getUid()) == PackageManager.PERMISSION_GRANTED;
+ }
+}
diff --git a/media/src/main/java/androidx/media/MediaSessionManagerImplApi28.java b/media/src/main/java/androidx/media/MediaSessionManagerImplApi28.java
new file mode 100644
index 0000000..48344fa
--- /dev/null
+++ b/media/src/main/java/androidx/media/MediaSessionManagerImplApi28.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media;
+
+import android.content.Context;
+
+import androidx.annotation.RequiresApi;
+
+@RequiresApi(28)
+class MediaSessionManagerImplApi28 extends MediaSessionManagerImplApi21 {
+ android.media.session.MediaSessionManager mObject;
+
+ MediaSessionManagerImplApi28(Context context) {
+ super(context);
+ mObject = (android.media.session.MediaSessionManager) context
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+ }
+
+ @Override
+ public boolean isTrustedForMediaControl(MediaSessionManager.RemoteUserInfoImpl userInfo) {
+ if (userInfo instanceof RemoteUserInfo) {
+ return mObject.isTrustedForMediaControl(((RemoteUserInfo) userInfo).mObject);
+ }
+ return false;
+ }
+
+ static final class RemoteUserInfo implements MediaSessionManager.RemoteUserInfoImpl {
+ android.media.session.MediaSessionManager.RemoteUserInfo mObject;
+
+ RemoteUserInfo(String packageName, int pid, int uid) {
+ mObject = new android.media.session.MediaSessionManager.RemoteUserInfo(
+ packageName, pid, uid);
+ }
+
+ @Override
+ public String getPackageName() {
+ return mObject.getPackageName();
+ }
+
+ @Override
+ public int getPid() {
+ return mObject.getPid();
+ }
+
+ @Override
+ public int getUid() {
+ return mObject.getUid();
+ }
+ }
+}
diff --git a/media/src/main/java/androidx/media/MediaSessionManagerImplBase.java b/media/src/main/java/androidx/media/MediaSessionManagerImplBase.java
new file mode 100644
index 0000000..6ff575e
--- /dev/null
+++ b/media/src/main/java/androidx/media/MediaSessionManagerImplBase.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media;
+
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.ObjectsCompat;
+
+class MediaSessionManagerImplBase implements MediaSessionManager.MediaSessionManagerImpl {
+ private static final String TAG = MediaSessionManager.TAG;
+ private static final boolean DEBUG = MediaSessionManager.DEBUG;
+
+ private static final String PERMISSION_STATUS_BAR_SERVICE =
+ "android.permission.STATUS_BAR_SERVICE";
+ private static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+
+ Context mContext;
+ ContentResolver mContentResolver;
+
+ MediaSessionManagerImplBase(Context context) {
+ mContext = context;
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public boolean isTrustedForMediaControl(
+ @NonNull MediaSessionManager.RemoteUserInfoImpl userInfo) {
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = mContext.getPackageManager().getApplicationInfo(
+ userInfo.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) {
+ Log.d(TAG, "Package " + userInfo.getPackageName() + " doesn't exist");
+ }
+ return false;
+ }
+
+ if (applicationInfo.uid != userInfo.getUid()) {
+ if (DEBUG) {
+ Log.d(TAG, "Package name " + userInfo.getPackageName()
+ + " doesn't match with the uid " + userInfo.getUid());
+ }
+ return false;
+ }
+ return mContext.checkPermission(PERMISSION_STATUS_BAR_SERVICE,
+ userInfo.getPid(), userInfo.getUid()) == PackageManager.PERMISSION_GRANTED
+ || userInfo.getUid() == Process.SYSTEM_UID
+ || isEnabledNotificationListener(userInfo);
+ }
+
+ /**
+ * This checks if the component is an enabled notification listener for the
+ * specified user. Enabled components may only operate on behalf of the user
+ * they're running as.
+ *
+ * @return True if the component is enabled, false otherwise
+ */
+ @SuppressWarnings("StringSplitter")
+ boolean isEnabledNotificationListener(
+ @NonNull MediaSessionManager.RemoteUserInfoImpl userInfo) {
+ final String enabledNotifListeners = Settings.Secure.getString(mContentResolver,
+ ENABLED_NOTIFICATION_LISTENERS);
+ if (enabledNotifListeners != null) {
+ final String[] components = enabledNotifListeners.split(":");
+ for (int i = 0; i < components.length; i++) {
+ final ComponentName component =
+ ComponentName.unflattenFromString(components[i]);
+ if (component != null) {
+ if (component.getPackageName().equals(userInfo.getPackageName())) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ static class RemoteUserInfo implements MediaSessionManager.RemoteUserInfoImpl {
+ private String mPackageName;
+ private int mPid;
+ private int mUid;
+
+ RemoteUserInfo(String packageName, int pid, int uid) {
+ mPackageName = packageName;
+ mPid = pid;
+ mUid = uid;
+ }
+
+ @Override
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public int getPid() {
+ return mPid;
+ }
+
+ @Override
+ public int getUid() {
+ return mUid;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof RemoteUserInfo)) {
+ return false;
+ }
+ RemoteUserInfo otherUserInfo = (RemoteUserInfo) obj;
+ return TextUtils.equals(mPackageName, otherUserInfo.mPackageName)
+ && mPid == otherUserInfo.mPid
+ && mUid == otherUserInfo.mUid;
+ }
+
+ @Override
+ public int hashCode() {
+ return ObjectsCompat.hash(mPackageName, mPid, mUid);
+ }
+ }
+}
+
diff --git a/media/src/main/java/androidx/media/MediaSessionService2.java b/media/src/main/java/androidx/media/MediaSessionService2.java
index 7bad65c..81dc877 100644
--- a/media/src/main/java/androidx/media/MediaSessionService2.java
+++ b/media/src/main/java/androidx/media/MediaSessionService2.java
@@ -97,7 +97,6 @@
* <p>
* After the binding, session's
* {@link MediaSession2.SessionCallback#onConnect(MediaSession2, ControllerInfo)}
- *
* will be called to accept or reject connection request from a controller. If the connection is
* rejected, the controller will unbind. If it's accepted, the controller will be available to use
* and keep binding.
@@ -106,6 +105,9 @@
* is called and service would become a foreground service. It's needed to keep playback after the
* controller is destroyed. The session service becomes background service when the playback is
* stopped.
+ * <p>
+ * The service is destroyed when the session is closed, or no media controller is bounded to the
+ * session while the service is not running as a foreground service.
* <a name="Permissions"></a>
* <h3>Permissions</h3>
* <p>
diff --git a/media/src/main/java/androidx/media/MediaUtils2.java b/media/src/main/java/androidx/media/MediaUtils2.java
index 657e24d..9d68623 100644
--- a/media/src/main/java/androidx/media/MediaUtils2.java
+++ b/media/src/main/java/androidx/media/MediaUtils2.java
@@ -428,4 +428,8 @@
static boolean isDefaultLibraryRootHint(Bundle bundle) {
return bundle != null && bundle.getBoolean(MediaConstants2.ROOT_EXTRA_DEFAULT, false);
}
+
+ static Bundle createBundle(Bundle bundle) {
+ return (bundle == null) ? new Bundle() : new Bundle(bundle);
+ }
}
diff --git a/media/src/main/java/androidx/media/SessionToken2.java b/media/src/main/java/androidx/media/SessionToken2.java
index eb42297..18c436c 100644
--- a/media/src/main/java/androidx/media/SessionToken2.java
+++ b/media/src/main/java/androidx/media/SessionToken2.java
@@ -23,7 +23,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.media.session.MediaSessionManager;
import android.os.Bundle;
import android.support.v4.media.session.MediaSessionCompat;
import android.text.TextUtils;
@@ -43,7 +42,7 @@
* This may be passed to apps by the session owner to allow them to create a
* {@link MediaController2} to communicate with the session.
* <p>
- * It can be also obtained by {@link MediaSessionManager}.
+ * It can be also obtained by MediaSessionManager.
*/
// New version of MediaSession.Token for following reasons
// - Stop implementing Parcelable for updatable support
diff --git a/media/src/main/java/androidx/media/subtitle/Cea608CCParser.java b/media/src/main/java/androidx/media/subtitle/Cea608CCParser.java
new file mode 100644
index 0000000..9205fba
--- /dev/null
+++ b/media/src/main/java/androidx/media/subtitle/Cea608CCParser.java
@@ -0,0 +1,987 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.subtitle;
+
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+import android.text.style.StyleSpan;
+import android.text.style.UnderlineSpan;
+import android.text.style.UpdateAppearance;
+import android.util.Log;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * CCParser processes CEA-608 closed caption data.
+ *
+ * It calls back into OnDisplayChangedListener upon
+ * display change with styled text for rendering.
+ *
+ */
+class Cea608CCParser {
+ public static final int MAX_ROWS = 15;
+ public static final int MAX_COLS = 32;
+
+ private static final String TAG = "Cea608CCParser";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final int INVALID = -1;
+
+ // EIA-CEA-608: Table 70 - Control Codes
+ private static final int RCL = 0x20;
+ private static final int BS = 0x21;
+ private static final int AOF = 0x22;
+ private static final int AON = 0x23;
+ private static final int DER = 0x24;
+ private static final int RU2 = 0x25;
+ private static final int RU3 = 0x26;
+ private static final int RU4 = 0x27;
+ private static final int FON = 0x28;
+ private static final int RDC = 0x29;
+ private static final int TR = 0x2a;
+ private static final int RTD = 0x2b;
+ private static final int EDM = 0x2c;
+ private static final int CR = 0x2d;
+ private static final int ENM = 0x2e;
+ private static final int EOC = 0x2f;
+
+ // Transparent Space
+ private static final char TS = '\u00A0';
+
+ // Captioning Modes
+ private static final int MODE_UNKNOWN = 0;
+ private static final int MODE_PAINT_ON = 1;
+ private static final int MODE_ROLL_UP = 2;
+ private static final int MODE_POP_ON = 3;
+ private static final int MODE_TEXT = 4;
+
+ private final DisplayListener mListener;
+
+ private int mMode = MODE_PAINT_ON;
+ private int mRollUpSize = 4;
+ private int mPrevCtrlCode = INVALID;
+
+ private CCMemory mDisplay = new CCMemory();
+ private CCMemory mNonDisplay = new CCMemory();
+ private CCMemory mTextMem = new CCMemory();
+
+ Cea608CCParser(DisplayListener listener) {
+ mListener = listener;
+ }
+
+ public void parse(byte[] data) {
+ CCData[] ccData = CCData.fromByteArray(data);
+
+ for (int i = 0; i < ccData.length; i++) {
+ if (DEBUG) {
+ Log.d(TAG, ccData[i].toString());
+ }
+
+ if (handleCtrlCode(ccData[i])
+ || handleTabOffsets(ccData[i])
+ || handlePACCode(ccData[i])
+ || handleMidRowCode(ccData[i])) {
+ continue;
+ }
+
+ handleDisplayableChars(ccData[i]);
+ }
+ }
+
+ interface DisplayListener {
+ void onDisplayChanged(SpannableStringBuilder[] styledTexts);
+ CaptionStyle getCaptionStyle();
+ }
+
+ private CCMemory getMemory() {
+ // get the CC memory to operate on for current mode
+ switch (mMode) {
+ case MODE_POP_ON:
+ return mNonDisplay;
+ case MODE_TEXT:
+ // TODO(chz): support only caption mode for now,
+ // in text mode, dump everything to text mem.
+ return mTextMem;
+ case MODE_PAINT_ON:
+ case MODE_ROLL_UP:
+ return mDisplay;
+ default:
+ Log.w(TAG, "unrecoginized mode: " + mMode);
+ }
+ return mDisplay;
+ }
+
+ private boolean handleDisplayableChars(CCData ccData) {
+ if (!ccData.isDisplayableChar()) {
+ return false;
+ }
+
+ // Extended char includes 1 automatic backspace
+ if (ccData.isExtendedChar()) {
+ getMemory().bs();
+ }
+
+ getMemory().writeText(ccData.getDisplayText());
+
+ if (mMode == MODE_PAINT_ON || mMode == MODE_ROLL_UP) {
+ updateDisplay();
+ }
+
+ return true;
+ }
+
+ private boolean handleMidRowCode(CCData ccData) {
+ StyleCode m = ccData.getMidRow();
+ if (m != null) {
+ getMemory().writeMidRowCode(m);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean handlePACCode(CCData ccData) {
+ PAC pac = ccData.getPAC();
+
+ if (pac != null) {
+ if (mMode == MODE_ROLL_UP) {
+ getMemory().moveBaselineTo(pac.getRow(), mRollUpSize);
+ }
+ getMemory().writePAC(pac);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean handleTabOffsets(CCData ccData) {
+ int tabs = ccData.getTabOffset();
+
+ if (tabs > 0) {
+ getMemory().tab(tabs);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean handleCtrlCode(CCData ccData) {
+ int ctrlCode = ccData.getCtrlCode();
+
+ if (mPrevCtrlCode != INVALID && mPrevCtrlCode == ctrlCode) {
+ // discard double ctrl codes (but if there's a 3rd one, we still take that)
+ mPrevCtrlCode = INVALID;
+ return true;
+ }
+
+ switch(ctrlCode) {
+ case RCL:
+ // select pop-on style
+ mMode = MODE_POP_ON;
+ break;
+ case BS:
+ getMemory().bs();
+ break;
+ case DER:
+ getMemory().der();
+ break;
+ case RU2:
+ case RU3:
+ case RU4:
+ mRollUpSize = (ctrlCode - 0x23);
+ // erase memory if currently in other style
+ if (mMode != MODE_ROLL_UP) {
+ mDisplay.erase();
+ mNonDisplay.erase();
+ }
+ // select roll-up style
+ mMode = MODE_ROLL_UP;
+ break;
+ case FON:
+ Log.i(TAG, "Flash On");
+ break;
+ case RDC:
+ // select paint-on style
+ mMode = MODE_PAINT_ON;
+ break;
+ case TR:
+ mMode = MODE_TEXT;
+ mTextMem.erase();
+ break;
+ case RTD:
+ mMode = MODE_TEXT;
+ break;
+ case EDM:
+ // erase display memory
+ mDisplay.erase();
+ updateDisplay();
+ break;
+ case CR:
+ if (mMode == MODE_ROLL_UP) {
+ getMemory().rollUp(mRollUpSize);
+ } else {
+ getMemory().cr();
+ }
+ if (mMode == MODE_ROLL_UP) {
+ updateDisplay();
+ }
+ break;
+ case ENM:
+ // erase non-display memory
+ mNonDisplay.erase();
+ break;
+ case EOC:
+ // swap display/non-display memory
+ swapMemory();
+ // switch to pop-on style
+ mMode = MODE_POP_ON;
+ updateDisplay();
+ break;
+ case INVALID:
+ default:
+ mPrevCtrlCode = INVALID;
+ return false;
+ }
+
+ mPrevCtrlCode = ctrlCode;
+
+ // handled
+ return true;
+ }
+
+ private void updateDisplay() {
+ if (mListener != null) {
+ CaptionStyle captionStyle = mListener.getCaptionStyle();
+ mListener.onDisplayChanged(mDisplay.getStyledText(captionStyle));
+ }
+ }
+
+ private void swapMemory() {
+ CCMemory temp = mDisplay;
+ mDisplay = mNonDisplay;
+ mNonDisplay = temp;
+ }
+
+ private static class StyleCode {
+ static final int COLOR_WHITE = 0;
+ static final int COLOR_GREEN = 1;
+ static final int COLOR_BLUE = 2;
+ static final int COLOR_CYAN = 3;
+ static final int COLOR_RED = 4;
+ static final int COLOR_YELLOW = 5;
+ static final int COLOR_MAGENTA = 6;
+ static final int COLOR_INVALID = 7;
+
+ static final int STYLE_ITALICS = 0x00000001;
+ static final int STYLE_UNDERLINE = 0x00000002;
+
+ static final String[] sColorMap = {
+ "WHITE", "GREEN", "BLUE", "CYAN", "RED", "YELLOW", "MAGENTA", "INVALID"
+ };
+
+ final int mStyle;
+ final int mColor;
+
+ static StyleCode fromByte(byte data2) {
+ int style = 0;
+ int color = (data2 >> 1) & 0x7;
+
+ if ((data2 & 0x1) != 0) {
+ style |= STYLE_UNDERLINE;
+ }
+
+ if (color == COLOR_INVALID) {
+ // WHITE ITALICS
+ color = COLOR_WHITE;
+ style |= STYLE_ITALICS;
+ }
+
+ return new StyleCode(style, color);
+ }
+
+ StyleCode(int style, int color) {
+ mStyle = style;
+ mColor = color;
+ }
+
+ boolean isItalics() {
+ return (mStyle & STYLE_ITALICS) != 0;
+ }
+
+ boolean isUnderline() {
+ return (mStyle & STYLE_UNDERLINE) != 0;
+ }
+
+ int getColor() {
+ return mColor;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ str.append("{");
+ str.append(sColorMap[mColor]);
+ if ((mStyle & STYLE_ITALICS) != 0) {
+ str.append(", ITALICS");
+ }
+ if ((mStyle & STYLE_UNDERLINE) != 0) {
+ str.append(", UNDERLINE");
+ }
+ str.append("}");
+
+ return str.toString();
+ }
+ }
+
+ private static class PAC extends StyleCode {
+ final int mRow;
+ final int mCol;
+
+ static PAC fromBytes(byte data1, byte data2) {
+ int[] rowTable = {11, 1, 3, 12, 14, 5, 7, 9};
+ int row = rowTable[data1 & 0x07] + ((data2 & 0x20) >> 5);
+ int style = 0;
+ if ((data2 & 1) != 0) {
+ style |= STYLE_UNDERLINE;
+ }
+ if ((data2 & 0x10) != 0) {
+ // indent code
+ int indent = (data2 >> 1) & 0x7;
+ return new PAC(row, indent * 4, style, COLOR_WHITE);
+ } else {
+ // style code
+ int color = (data2 >> 1) & 0x7;
+
+ if (color == COLOR_INVALID) {
+ // WHITE ITALICS
+ color = COLOR_WHITE;
+ style |= STYLE_ITALICS;
+ }
+ return new PAC(row, -1, style, color);
+ }
+ }
+
+ PAC(int row, int col, int style, int color) {
+ super(style, color);
+ mRow = row;
+ mCol = col;
+ }
+
+ boolean isIndentPAC() {
+ return (mCol >= 0);
+ }
+
+ int getRow() {
+ return mRow;
+ }
+
+ int getCol() {
+ return mCol;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{%d, %d}, %s",
+ mRow, mCol, super.toString());
+ }
+ }
+
+ /**
+ * Mutable version of BackgroundSpan to facilitate text rendering with edge styles.
+ */
+ public static class MutableBackgroundColorSpan extends CharacterStyle
+ implements UpdateAppearance {
+ private int mColor;
+
+ MutableBackgroundColorSpan(int color) {
+ mColor = color;
+ }
+
+ public void setBackgroundColor(int color) {
+ mColor = color;
+ }
+
+ public int getBackgroundColor() {
+ return mColor;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ ds.bgColor = mColor;
+ }
+ }
+
+ /* CCLineBuilder keeps track of displayable chars, as well as
+ * MidRow styles and PACs, for a single line of CC memory.
+ *
+ * It generates styled text via getStyledText() method.
+ */
+ private static class CCLineBuilder {
+ private final StringBuilder mDisplayChars;
+ private final StyleCode[] mMidRowStyles;
+ private final StyleCode[] mPACStyles;
+
+ CCLineBuilder(String str) {
+ mDisplayChars = new StringBuilder(str);
+ mMidRowStyles = new StyleCode[mDisplayChars.length()];
+ mPACStyles = new StyleCode[mDisplayChars.length()];
+ }
+
+ void setCharAt(int index, char ch) {
+ mDisplayChars.setCharAt(index, ch);
+ mMidRowStyles[index] = null;
+ }
+
+ void setMidRowAt(int index, StyleCode m) {
+ mDisplayChars.setCharAt(index, ' ');
+ mMidRowStyles[index] = m;
+ }
+
+ void setPACAt(int index, PAC pac) {
+ mPACStyles[index] = pac;
+ }
+
+ char charAt(int index) {
+ return mDisplayChars.charAt(index);
+ }
+
+ int length() {
+ return mDisplayChars.length();
+ }
+
+ void applyStyleSpan(
+ SpannableStringBuilder styledText,
+ StyleCode s, int start, int end) {
+ if (s.isItalics()) {
+ styledText.setSpan(
+ new StyleSpan(android.graphics.Typeface.ITALIC),
+ start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ if (s.isUnderline()) {
+ styledText.setSpan(
+ new UnderlineSpan(),
+ start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ SpannableStringBuilder getStyledText(CaptionStyle captionStyle) {
+ SpannableStringBuilder styledText = new SpannableStringBuilder(mDisplayChars);
+ int start = -1, next = 0;
+ int styleStart = -1;
+ StyleCode curStyle = null;
+ while (next < mDisplayChars.length()) {
+ StyleCode newStyle = null;
+ if (mMidRowStyles[next] != null) {
+ // apply mid-row style change
+ newStyle = mMidRowStyles[next];
+ } else if (mPACStyles[next] != null && (styleStart < 0 || start < 0)) {
+ // apply PAC style change, only if:
+ // 1. no style set, or
+ // 2. style set, but prev char is none-displayable
+ newStyle = mPACStyles[next];
+ }
+ if (newStyle != null) {
+ curStyle = newStyle;
+ if (styleStart >= 0 && start >= 0) {
+ applyStyleSpan(styledText, newStyle, styleStart, next);
+ }
+ styleStart = next;
+ }
+
+ if (mDisplayChars.charAt(next) != TS) {
+ if (start < 0) {
+ start = next;
+ }
+ } else if (start >= 0) {
+ int expandedStart = mDisplayChars.charAt(start) == ' ' ? start : start - 1;
+ int expandedEnd = mDisplayChars.charAt(next - 1) == ' ' ? next : next + 1;
+ styledText.setSpan(
+ new MutableBackgroundColorSpan(captionStyle.backgroundColor),
+ expandedStart, expandedEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ if (styleStart >= 0) {
+ applyStyleSpan(styledText, curStyle, styleStart, expandedEnd);
+ }
+ start = -1;
+ }
+ next++;
+ }
+
+ return styledText;
+ }
+ }
+
+ /*
+ * CCMemory models a console-style display.
+ */
+ private static class CCMemory {
+ private final String mBlankLine;
+ private final CCLineBuilder[] mLines = new CCLineBuilder[MAX_ROWS + 2];
+ private int mRow;
+ private int mCol;
+
+ CCMemory() {
+ char[] blank = new char[MAX_COLS + 2];
+ Arrays.fill(blank, TS);
+ mBlankLine = new String(blank);
+ }
+
+ void erase() {
+ // erase all lines
+ for (int i = 0; i < mLines.length; i++) {
+ mLines[i] = null;
+ }
+ mRow = MAX_ROWS;
+ mCol = 1;
+ }
+
+ void der() {
+ if (mLines[mRow] != null) {
+ for (int i = 0; i < mCol; i++) {
+ if (mLines[mRow].charAt(i) != TS) {
+ for (int j = mCol; j < mLines[mRow].length(); j++) {
+ mLines[j].setCharAt(j, TS);
+ }
+ return;
+ }
+ }
+ mLines[mRow] = null;
+ }
+ }
+
+ void tab(int tabs) {
+ moveCursorByCol(tabs);
+ }
+
+ void bs() {
+ moveCursorByCol(-1);
+ if (mLines[mRow] != null) {
+ mLines[mRow].setCharAt(mCol, TS);
+ if (mCol == MAX_COLS - 1) {
+ // Spec recommendation:
+ // if cursor was at col 32, move cursor
+ // back to col 31 and erase both col 31&32
+ mLines[mRow].setCharAt(MAX_COLS, TS);
+ }
+ }
+ }
+
+ void cr() {
+ moveCursorTo(mRow + 1, 1);
+ }
+
+ void rollUp(int windowSize) {
+ int i;
+ for (i = 0; i <= mRow - windowSize; i++) {
+ mLines[i] = null;
+ }
+ int startRow = mRow - windowSize + 1;
+ if (startRow < 1) {
+ startRow = 1;
+ }
+ for (i = startRow; i < mRow; i++) {
+ mLines[i] = mLines[i + 1];
+ }
+ for (i = mRow; i < mLines.length; i++) {
+ // clear base row
+ mLines[i] = null;
+ }
+ // default to col 1, in case PAC is not sent
+ mCol = 1;
+ }
+
+ void writeText(String text) {
+ for (int i = 0; i < text.length(); i++) {
+ getLineBuffer(mRow).setCharAt(mCol, text.charAt(i));
+ moveCursorByCol(1);
+ }
+ }
+
+ void writeMidRowCode(StyleCode m) {
+ getLineBuffer(mRow).setMidRowAt(mCol, m);
+ moveCursorByCol(1);
+ }
+
+ void writePAC(PAC pac) {
+ if (pac.isIndentPAC()) {
+ moveCursorTo(pac.getRow(), pac.getCol());
+ } else {
+ moveCursorTo(pac.getRow(), 1);
+ }
+ getLineBuffer(mRow).setPACAt(mCol, pac);
+ }
+
+ SpannableStringBuilder[] getStyledText(CaptionStyle captionStyle) {
+ ArrayList<SpannableStringBuilder> rows = new ArrayList<>(MAX_ROWS);
+ for (int i = 1; i <= MAX_ROWS; i++) {
+ rows.add(mLines[i] != null ? mLines[i].getStyledText(captionStyle) : null);
+ }
+ return rows.toArray(new SpannableStringBuilder[MAX_ROWS]);
+ }
+
+ private static int clamp(int x, int min, int max) {
+ return x < min ? min : (x > max ? max : x);
+ }
+
+ private void moveCursorTo(int row, int col) {
+ mRow = clamp(row, 1, MAX_ROWS);
+ mCol = clamp(col, 1, MAX_COLS);
+ }
+
+ private void moveCursorToRow(int row) {
+ mRow = clamp(row, 1, MAX_ROWS);
+ }
+
+ private void moveCursorByCol(int col) {
+ mCol = clamp(mCol + col, 1, MAX_COLS);
+ }
+
+ private void moveBaselineTo(int baseRow, int windowSize) {
+ if (mRow == baseRow) {
+ return;
+ }
+ int actualWindowSize = windowSize;
+ if (baseRow < actualWindowSize) {
+ actualWindowSize = baseRow;
+ }
+ if (mRow < actualWindowSize) {
+ actualWindowSize = mRow;
+ }
+
+ int i;
+ if (baseRow < mRow) {
+ // copy from bottom to top row
+ for (i = actualWindowSize - 1; i >= 0; i--) {
+ mLines[baseRow - i] = mLines[mRow - i];
+ }
+ } else {
+ // copy from top to bottom row
+ for (i = 0; i < actualWindowSize; i++) {
+ mLines[baseRow - i] = mLines[mRow - i];
+ }
+ }
+ // clear rest of the rows
+ for (i = 0; i <= baseRow - windowSize; i++) {
+ mLines[i] = null;
+ }
+ for (i = baseRow + 1; i < mLines.length; i++) {
+ mLines[i] = null;
+ }
+ }
+
+ private CCLineBuilder getLineBuffer(int row) {
+ if (mLines[row] == null) {
+ mLines[row] = new CCLineBuilder(mBlankLine);
+ }
+ return mLines[row];
+ }
+ }
+
+ /*
+ * CCData parses the raw CC byte pair into displayable chars,
+ * misc control codes, Mid-Row or Preamble Address Codes.
+ */
+ private static class CCData {
+ private final byte mType;
+ private final byte mData1;
+ private final byte mData2;
+
+ private static final String[] sCtrlCodeMap = {
+ "RCL", "BS" , "AOF", "AON",
+ "DER", "RU2", "RU3", "RU4",
+ "FON", "RDC", "TR" , "RTD",
+ "EDM", "CR" , "ENM", "EOC",
+ };
+
+ private static final String[] sSpecialCharMap = {
+ "\u00AE",
+ "\u00B0",
+ "\u00BD",
+ "\u00BF",
+ "\u2122",
+ "\u00A2",
+ "\u00A3",
+ "\u266A", // Eighth note
+ "\u00E0",
+ "\u00A0", // Transparent space
+ "\u00E8",
+ "\u00E2",
+ "\u00EA",
+ "\u00EE",
+ "\u00F4",
+ "\u00FB",
+ };
+
+ private static final String[] sSpanishCharMap = {
+ // Spanish and misc chars
+ "\u00C1", // A
+ "\u00C9", // E
+ "\u00D3", // I
+ "\u00DA", // O
+ "\u00DC", // U
+ "\u00FC", // u
+ "\u2018", // opening single quote
+ "\u00A1", // inverted exclamation mark
+ "*",
+ "'",
+ "\u2014", // em dash
+ "\u00A9", // Copyright
+ "\u2120", // Servicemark
+ "\u2022", // round bullet
+ "\u201C", // opening double quote
+ "\u201D", // closing double quote
+ // French
+ "\u00C0",
+ "\u00C2",
+ "\u00C7",
+ "\u00C8",
+ "\u00CA",
+ "\u00CB",
+ "\u00EB",
+ "\u00CE",
+ "\u00CF",
+ "\u00EF",
+ "\u00D4",
+ "\u00D9",
+ "\u00F9",
+ "\u00DB",
+ "\u00AB",
+ "\u00BB"
+ };
+
+ private static final String[] sProtugueseCharMap = {
+ // Portuguese
+ "\u00C3",
+ "\u00E3",
+ "\u00CD",
+ "\u00CC",
+ "\u00EC",
+ "\u00D2",
+ "\u00F2",
+ "\u00D5",
+ "\u00F5",
+ "{",
+ "}",
+ "\\",
+ "^",
+ "_",
+ "|",
+ "~",
+ // German and misc chars
+ "\u00C4",
+ "\u00E4",
+ "\u00D6",
+ "\u00F6",
+ "\u00DF",
+ "\u00A5",
+ "\u00A4",
+ "\u2502", // vertical bar
+ "\u00C5",
+ "\u00E5",
+ "\u00D8",
+ "\u00F8",
+ "\u250C", // top-left corner
+ "\u2510", // top-right corner
+ "\u2514", // lower-left corner
+ "\u2518", // lower-right corner
+ };
+
+ static CCData[] fromByteArray(byte[] data) {
+ CCData[] ccData = new CCData[data.length / 3];
+
+ for (int i = 0; i < ccData.length; i++) {
+ ccData[i] = new CCData(
+ data[i * 3],
+ data[i * 3 + 1],
+ data[i * 3 + 2]);
+ }
+
+ return ccData;
+ }
+
+ CCData(byte type, byte data1, byte data2) {
+ mType = type;
+ mData1 = data1;
+ mData2 = data2;
+ }
+
+ int getCtrlCode() {
+ if ((mData1 == 0x14 || mData1 == 0x1c)
+ && mData2 >= 0x20 && mData2 <= 0x2f) {
+ return mData2;
+ }
+ return INVALID;
+ }
+
+ StyleCode getMidRow() {
+ // only support standard Mid-row codes, ignore
+ // optional background/foreground mid-row codes
+ if ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x20 && mData2 <= 0x2f) {
+ return StyleCode.fromByte(mData2);
+ }
+ return null;
+ }
+
+ PAC getPAC() {
+ if ((mData1 & 0x70) == 0x10
+ && (mData2 & 0x40) == 0x40
+ && ((mData1 & 0x07) != 0 || (mData2 & 0x20) == 0)) {
+ return PAC.fromBytes(mData1, mData2);
+ }
+ return null;
+ }
+
+ int getTabOffset() {
+ if ((mData1 == 0x17 || mData1 == 0x1f)
+ && mData2 >= 0x21 && mData2 <= 0x23) {
+ return mData2 & 0x3;
+ }
+ return 0;
+ }
+
+ boolean isDisplayableChar() {
+ return isBasicChar() || isSpecialChar() || isExtendedChar();
+ }
+
+ String getDisplayText() {
+ String str = getBasicChars();
+
+ if (str == null) {
+ str = getSpecialChar();
+
+ if (str == null) {
+ str = getExtendedChar();
+ }
+ }
+
+ return str;
+ }
+
+ private String ctrlCodeToString(int ctrlCode) {
+ return sCtrlCodeMap[ctrlCode - 0x20];
+ }
+
+ private boolean isBasicChar() {
+ return mData1 >= 0x20 && mData1 <= 0x7f;
+ }
+
+ private boolean isSpecialChar() {
+ return ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x30 && mData2 <= 0x3f);
+ }
+
+ private boolean isExtendedChar() {
+ return ((mData1 == 0x12 || mData1 == 0x1A
+ || mData1 == 0x13 || mData1 == 0x1B)
+ && mData2 >= 0x20 && mData2 <= 0x3f);
+ }
+
+ private char getBasicChar(byte data) {
+ char c;
+ // replace the non-ASCII ones
+ switch (data) {
+ case 0x2A: c = '\u00E1'; break;
+ case 0x5C: c = '\u00E9'; break;
+ case 0x5E: c = '\u00ED'; break;
+ case 0x5F: c = '\u00F3'; break;
+ case 0x60: c = '\u00FA'; break;
+ case 0x7B: c = '\u00E7'; break;
+ case 0x7C: c = '\u00F7'; break;
+ case 0x7D: c = '\u00D1'; break;
+ case 0x7E: c = '\u00F1'; break;
+ case 0x7F: c = '\u2588'; break; // Full block
+ default: c = (char) data; break;
+ }
+ return c;
+ }
+
+ private String getBasicChars() {
+ if (mData1 >= 0x20 && mData1 <= 0x7f) {
+ StringBuilder builder = new StringBuilder(2);
+ builder.append(getBasicChar(mData1));
+ if (mData2 >= 0x20 && mData2 <= 0x7f) {
+ builder.append(getBasicChar(mData2));
+ }
+ return builder.toString();
+ }
+
+ return null;
+ }
+
+ private String getSpecialChar() {
+ if ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x30 && mData2 <= 0x3f) {
+ return sSpecialCharMap[mData2 - 0x30];
+ }
+
+ return null;
+ }
+
+ private String getExtendedChar() {
+ if ((mData1 == 0x12 || mData1 == 0x1A) && mData2 >= 0x20 && mData2 <= 0x3f) {
+ // 1 Spanish/French char
+ return sSpanishCharMap[mData2 - 0x20];
+ } else if ((mData1 == 0x13 || mData1 == 0x1B) && mData2 >= 0x20 && mData2 <= 0x3f) {
+ // 1 Portuguese/German/Danish char
+ return sProtugueseCharMap[mData2 - 0x20];
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ String str;
+
+ if (mData1 < 0x10 && mData2 < 0x10) {
+ // Null Pad, ignore
+ return String.format("[%d]Null: %02x %02x", mType, mData1, mData2);
+ }
+
+ int ctrlCode = getCtrlCode();
+ if (ctrlCode != INVALID) {
+ return String.format("[%d]%s", mType, ctrlCodeToString(ctrlCode));
+ }
+
+ int tabOffset = getTabOffset();
+ if (tabOffset > 0) {
+ return String.format("[%d]Tab%d", mType, tabOffset);
+ }
+
+ PAC pac = getPAC();
+ if (pac != null) {
+ return String.format("[%d]PAC: %s", mType, pac.toString());
+ }
+
+ StyleCode m = getMidRow();
+ if (m != null) {
+ return String.format("[%d]Mid-row: %s", mType, m.toString());
+ }
+
+ if (isDisplayableChar()) {
+ return String.format("[%d]Displayable: %s (%02x %02x)",
+ mType, getDisplayText(), mData1, mData2);
+ }
+
+ return String.format("[%d]Invalid: %02x %02x", mType, mData1, mData2);
+ }
+ }
+}
diff --git a/media/src/main/java/androidx/media/subtitle/ClosedCaptionRenderer.java b/media/src/main/java/androidx/media/subtitle/ClosedCaptionRenderer.java
new file mode 100644
index 0000000..90ff516
--- /dev/null
+++ b/media/src/main/java/androidx/media/subtitle/ClosedCaptionRenderer.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.subtitle;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.media.MediaFormat;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.media.R;
+
+import java.util.ArrayList;
+
+// Note: This is forked from android.media.ClosedCaptionRenderer since P
+/**
+ * @hide
+ */
+@RequiresApi(28)
+@RestrictTo(LIBRARY_GROUP)
+public class ClosedCaptionRenderer extends SubtitleController.Renderer {
+ private final Context mContext;
+ private Cea608CCWidget mCCWidget;
+
+ public ClosedCaptionRenderer(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public boolean supports(MediaFormat format) {
+ if (format.containsKey(MediaFormat.KEY_MIME)) {
+ String mimeType = format.getString(MediaFormat.KEY_MIME);
+ return MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mimeType);
+ }
+ return false;
+ }
+
+ @Override
+ public SubtitleTrack createTrack(MediaFormat format) {
+ String mimeType = format.getString(MediaFormat.KEY_MIME);
+ if (MediaFormat.MIMETYPE_TEXT_CEA_608.equals(mimeType)) {
+ if (mCCWidget == null) {
+ mCCWidget = new Cea608CCWidget(mContext);
+ }
+ return new Cea608CaptionTrack(mCCWidget, format);
+ }
+ throw new RuntimeException("No matching format: " + format.toString());
+ }
+
+ static class Cea608CaptionTrack extends SubtitleTrack {
+ private final Cea608CCParser mCCParser;
+ private final Cea608CCWidget mRenderingWidget;
+
+ Cea608CaptionTrack(Cea608CCWidget renderingWidget, MediaFormat format) {
+ super(format);
+
+ mRenderingWidget = renderingWidget;
+ mCCParser = new Cea608CCParser(mRenderingWidget);
+ }
+
+ @Override
+ public void onData(byte[] data, boolean eos, long runID) {
+ mCCParser.parse(data);
+ }
+
+ @Override
+ public RenderingWidget getRenderingWidget() {
+ return mRenderingWidget;
+ }
+
+ @Override
+ public void updateView(ArrayList<Cue> activeCues) {
+ // Overriding with NO-OP, CC rendering by-passes this
+ }
+ }
+
+ /**
+ * Widget capable of rendering CEA-608 closed captions.
+ */
+ class Cea608CCWidget extends ClosedCaptionWidget implements Cea608CCParser.DisplayListener {
+ private static final String DUMMY_TEXT = "1234567890123456789012345678901234";
+ private final Rect mTextBounds = new Rect();
+
+ Cea608CCWidget(Context context) {
+ this(context, null);
+ }
+
+ Cea608CCWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ Cea608CCWidget(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, 0);
+ }
+
+ Cea608CCWidget(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public ClosedCaptionLayout createCaptionLayout(Context context) {
+ return new CCLayout(context);
+ }
+
+ @Override
+ public void onDisplayChanged(SpannableStringBuilder[] styledTexts) {
+ ((CCLayout) mClosedCaptionLayout).update(styledTexts);
+
+ if (mListener != null) {
+ mListener.onChanged(this);
+ }
+ }
+
+ @Override
+ public CaptionStyle getCaptionStyle() {
+ return mCaptionStyle;
+ }
+
+ private class CCLineBox extends TextView {
+ private static final float FONT_PADDING_RATIO = 0.75f;
+ private static final float EDGE_OUTLINE_RATIO = 0.1f;
+ private static final float EDGE_SHADOW_RATIO = 0.05f;
+ private float mOutlineWidth;
+ private float mShadowRadius;
+ private float mShadowOffset;
+
+ private int mTextColor = Color.WHITE;
+ private int mBgColor = Color.BLACK;
+ private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
+ private int mEdgeColor = Color.TRANSPARENT;
+
+ CCLineBox(Context context) {
+ super(context);
+ setGravity(Gravity.CENTER);
+ setBackgroundColor(Color.TRANSPARENT);
+ setTextColor(Color.WHITE);
+ setTypeface(Typeface.MONOSPACE);
+ setVisibility(View.INVISIBLE);
+
+ final Resources res = getContext().getResources();
+
+ // get the default (will be updated later during measure)
+ mOutlineWidth = res.getDimensionPixelSize(
+ R.dimen.subtitle_outline_width);
+ mShadowRadius = res.getDimensionPixelSize(
+ R.dimen.subtitle_shadow_radius);
+ mShadowOffset = res.getDimensionPixelSize(
+ R.dimen.subtitle_shadow_offset);
+ }
+
+ void setCaptionStyle(CaptionStyle captionStyle) {
+ mTextColor = captionStyle.foregroundColor;
+ mBgColor = captionStyle.backgroundColor;
+ mEdgeType = captionStyle.edgeType;
+ mEdgeColor = captionStyle.edgeColor;
+
+ setTextColor(mTextColor);
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ setShadowLayer(mShadowRadius, mShadowOffset, mShadowOffset, mEdgeColor);
+ } else {
+ setShadowLayer(0, 0, 0, 0);
+ }
+ invalidate();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ float fontSize = MeasureSpec.getSize(heightMeasureSpec) * FONT_PADDING_RATIO;
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
+
+ mOutlineWidth = EDGE_OUTLINE_RATIO * fontSize + 1.0f;
+ mShadowRadius = EDGE_SHADOW_RATIO * fontSize + 1.0f;
+ mShadowOffset = mShadowRadius;
+
+ // set font scale in the X direction to match the required width
+ setScaleX(1.0f);
+ getPaint().getTextBounds(DUMMY_TEXT, 0, DUMMY_TEXT.length(), mTextBounds);
+ float actualTextWidth = mTextBounds.width();
+ float requiredTextWidth = MeasureSpec.getSize(widthMeasureSpec);
+ setScaleX(requiredTextWidth / actualTextWidth);
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onDraw(Canvas c) {
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_UNSPECIFIED
+ || mEdgeType == CaptionStyle.EDGE_TYPE_NONE
+ || mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ // these edge styles don't require a second pass
+ super.onDraw(c);
+ return;
+ }
+
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+ drawEdgeOutline(c);
+ } else {
+ // Raised or depressed
+ drawEdgeRaisedOrDepressed(c);
+ }
+ }
+
+ @SuppressWarnings("WrongCall")
+ private void drawEdgeOutline(Canvas c) {
+ TextPaint textPaint = getPaint();
+
+ Paint.Style previousStyle = textPaint.getStyle();
+ Paint.Join previousJoin = textPaint.getStrokeJoin();
+ float previousWidth = textPaint.getStrokeWidth();
+
+ setTextColor(mEdgeColor);
+ textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ textPaint.setStrokeJoin(Paint.Join.ROUND);
+ textPaint.setStrokeWidth(mOutlineWidth);
+
+ // Draw outline and background only.
+ super.onDraw(c);
+
+ // Restore original settings.
+ setTextColor(mTextColor);
+ textPaint.setStyle(previousStyle);
+ textPaint.setStrokeJoin(previousJoin);
+ textPaint.setStrokeWidth(previousWidth);
+
+ // Remove the background.
+ setBackgroundSpans(Color.TRANSPARENT);
+ // Draw foreground only.
+ super.onDraw(c);
+ // Restore the background.
+ setBackgroundSpans(mBgColor);
+ }
+
+ @SuppressWarnings("WrongCall")
+ private void drawEdgeRaisedOrDepressed(Canvas c) {
+ TextPaint textPaint = getPaint();
+
+ Paint.Style previousStyle = textPaint.getStyle();
+ textPaint.setStyle(Paint.Style.FILL);
+
+ final boolean raised = mEdgeType == CaptionStyle.EDGE_TYPE_RAISED;
+ final int colorUp = raised ? Color.WHITE : mEdgeColor;
+ final int colorDown = raised ? mEdgeColor : Color.WHITE;
+ final float offset = mShadowRadius / 2f;
+
+ // Draw background and text with shadow up
+ setShadowLayer(mShadowRadius, -offset, -offset, colorUp);
+ super.onDraw(c);
+
+ // Remove the background.
+ setBackgroundSpans(Color.TRANSPARENT);
+
+ // Draw text with shadow down
+ setShadowLayer(mShadowRadius, +offset, +offset, colorDown);
+ super.onDraw(c);
+
+ // Restore settings
+ textPaint.setStyle(previousStyle);
+
+ // Restore the background.
+ setBackgroundSpans(mBgColor);
+ }
+
+ private void setBackgroundSpans(int color) {
+ CharSequence text = getText();
+ if (text instanceof Spannable) {
+ Spannable spannable = (Spannable) text;
+ Cea608CCParser.MutableBackgroundColorSpan[] bgSpans = spannable.getSpans(
+ 0, spannable.length(), Cea608CCParser.MutableBackgroundColorSpan.class);
+ for (int i = 0; i < bgSpans.length; i++) {
+ bgSpans[i].setBackgroundColor(color);
+ }
+ }
+ }
+ }
+
+ private class CCLayout extends LinearLayout implements ClosedCaptionLayout {
+ private static final int MAX_ROWS = Cea608CCParser.MAX_ROWS;
+ private static final float SAFE_AREA_RATIO = 0.9f;
+
+ private final CCLineBox[] mLineBoxes = new CCLineBox[MAX_ROWS];
+
+ CCLayout(Context context) {
+ super(context);
+ setGravity(Gravity.START);
+ setOrientation(LinearLayout.VERTICAL);
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i] = new CCLineBox(getContext());
+ addView(mLineBoxes[i], LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+ }
+
+ @Override
+ public void setCaptionStyle(CaptionStyle captionStyle) {
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].setCaptionStyle(captionStyle);
+ }
+ }
+
+ @Override
+ public void setFontScale(float fontScale) {
+ // Ignores the font scale changes of the system wide CC preference.
+ }
+
+ void update(SpannableStringBuilder[] textBuffer) {
+ for (int i = 0; i < MAX_ROWS; i++) {
+ if (textBuffer[i] != null) {
+ mLineBoxes[i].setText(textBuffer[i], TextView.BufferType.SPANNABLE);
+ mLineBoxes[i].setVisibility(View.VISIBLE);
+ } else {
+ mLineBoxes[i].setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ int safeWidth = getMeasuredWidth();
+ int safeHeight = getMeasuredHeight();
+
+ // CEA-608 assumes 4:3 video
+ if (safeWidth * 3 >= safeHeight * 4) {
+ safeWidth = safeHeight * 4 / 3;
+ } else {
+ safeHeight = safeWidth * 3 / 4;
+ }
+ safeWidth = (int) (safeWidth * SAFE_AREA_RATIO);
+ safeHeight = (int) (safeHeight * SAFE_AREA_RATIO);
+
+ int lineHeight = safeHeight / MAX_ROWS;
+ int lineHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ lineHeight, MeasureSpec.EXACTLY);
+ int lineWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ safeWidth, MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].measure(lineWidthMeasureSpec, lineHeightMeasureSpec);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ // safe caption area
+ int viewPortWidth = r - l;
+ int viewPortHeight = b - t;
+ int safeWidth, safeHeight;
+ // CEA-608 assumes 4:3 video
+ if (viewPortWidth * 3 >= viewPortHeight * 4) {
+ safeWidth = viewPortHeight * 4 / 3;
+ safeHeight = viewPortHeight;
+ } else {
+ safeWidth = viewPortWidth;
+ safeHeight = viewPortWidth * 3 / 4;
+ }
+ safeWidth = (int) (safeWidth * SAFE_AREA_RATIO);
+ safeHeight = (int) (safeHeight * SAFE_AREA_RATIO);
+ int left = (viewPortWidth - safeWidth) / 2;
+ int top = (viewPortHeight - safeHeight) / 2;
+
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].layout(
+ left,
+ top + safeHeight * i / MAX_ROWS,
+ left + safeWidth,
+ top + safeHeight * (i + 1) / MAX_ROWS);
+ }
+ }
+ }
+ }
+}
diff --git a/media/src/main/java/androidx/media/subtitle/ClosedCaptionWidget.java b/media/src/main/java/androidx/media/subtitle/ClosedCaptionWidget.java
new file mode 100644
index 0000000..a3d3e47
--- /dev/null
+++ b/media/src/main/java/androidx/media/subtitle/ClosedCaptionWidget.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.subtitle;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+
+import androidx.annotation.RequiresApi;
+
+/**
+ * Abstract widget class to render a closed caption track.
+ */
+@RequiresApi(28)
+abstract class ClosedCaptionWidget extends ViewGroup implements SubtitleTrack.RenderingWidget {
+
+ interface ClosedCaptionLayout {
+ void setCaptionStyle(CaptionStyle captionStyle);
+ void setFontScale(float scale);
+ }
+
+ /** Captioning manager, used to obtain and track caption properties. */
+ private final CaptioningManager mManager;
+
+ /** Current caption style. */
+ protected CaptionStyle mCaptionStyle;
+
+ /** Callback for rendering changes. */
+ protected OnChangedListener mListener;
+
+ /** Concrete layout of CC. */
+ protected ClosedCaptionLayout mClosedCaptionLayout;
+
+ /** Whether a caption style change listener is registered. */
+ private boolean mHasChangeListener;
+
+ ClosedCaptionWidget(Context context) {
+ this(context, null);
+ }
+
+ ClosedCaptionWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, 0);
+ }
+
+ ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ // Cannot render text over video when layer type is hardware.
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ mCaptionStyle = mManager.getUserStyle();
+
+ mClosedCaptionLayout = createCaptionLayout(context);
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ mClosedCaptionLayout.setFontScale(mManager.getFontScale());
+ addView((ViewGroup) mClosedCaptionLayout, LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT);
+
+ requestLayout();
+ }
+
+ public abstract ClosedCaptionLayout createCaptionLayout(Context context);
+
+ @Override
+ public void setOnChangedListener(OnChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ measure(widthSpec, heightSpec);
+ layout(0, 0, width, height);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ ((ViewGroup) mClosedCaptionLayout).measure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ ((ViewGroup) mClosedCaptionLayout).layout(l, t, r, b);
+ }
+
+ /**
+ * Manages whether this renderer is listening for caption style changes.
+ */
+ private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+ @Override
+ public void onUserStyleChanged(CaptionStyle userStyle) {
+ mCaptionStyle = userStyle;
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ }
+
+ @Override
+ public void onFontScaleChanged(float fontScale) {
+ mClosedCaptionLayout.setFontScale(fontScale);
+ }
+ };
+
+ private void manageChangeListener() {
+ final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+ if (mHasChangeListener != needsListener) {
+ mHasChangeListener = needsListener;
+
+ if (needsListener) {
+ mManager.addCaptioningChangeListener(mCaptioningListener);
+ } else {
+ mManager.removeCaptioningChangeListener(mCaptioningListener);
+ }
+ }
+ }
+}
+
diff --git a/media/src/main/java/androidx/media/subtitle/MediaTimeProvider.java b/media/src/main/java/androidx/media/subtitle/MediaTimeProvider.java
new file mode 100644
index 0000000..b6f0a14
--- /dev/null
+++ b/media/src/main/java/androidx/media/subtitle/MediaTimeProvider.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.subtitle;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import androidx.annotation.RestrictTo;
+
+// Note: This is just copied from android.media.MediaTimeProvider.
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public interface MediaTimeProvider {
+ // we do not allow negative media time
+ /**
+ * Presentation time value if no timed event notification is requested.
+ */
+ long NO_TIME = -1;
+
+ /**
+ * Cancels all previous notification request from this listener if any. It
+ * registers the listener to get seek and stop notifications. If timeUs is
+ * not negative, it also registers the listener for a timed event
+ * notification when the presentation time reaches (becomes greater) than
+ * the value specified. This happens immediately if the current media time
+ * is larger than or equal to timeUs.
+ *
+ * @param timeUs presentation time to get timed event callback at (or
+ * {@link #NO_TIME})
+ */
+ void notifyAt(long timeUs, OnMediaTimeListener listener);
+
+ /**
+ * Cancels all previous notification request from this listener if any. It
+ * registers the listener to get seek and stop notifications. If the media
+ * is stopped, the listener will immediately receive a stop notification.
+ * Otherwise, it will receive a timed event notificaton.
+ */
+ void scheduleUpdate(OnMediaTimeListener listener);
+
+ /**
+ * Cancels all previous notification request from this listener if any.
+ */
+ void cancelNotifications(OnMediaTimeListener listener);
+
+ /**
+ * Get the current presentation time.
+ *
+ * @param precise Whether getting a precise time is important. This is
+ * more costly.
+ * @param monotonic Whether returned time should be monotonic: that is,
+ * greater than or equal to the last returned time. Don't
+ * always set this to true. E.g. this has undesired
+ * consequences if the media is seeked between calls.
+ * @throws IllegalStateException if the media is not initialized
+ */
+ long getCurrentTimeUs(boolean precise, boolean monotonic)
+ throws IllegalStateException;
+
+ /**
+ * Mediatime listener
+ */
+ public interface OnMediaTimeListener {
+ /**
+ * Called when the registered time was reached naturally.
+ *
+ * @param timeUs current media time
+ */
+ void onTimedEvent(long timeUs);
+
+ /**
+ * Called when the media time changed due to seeking.
+ *
+ * @param timeUs current media time
+ */
+ void onSeek(long timeUs);
+
+ /**
+ * Called when the playback stopped. This is not called on pause, only
+ * on full stop, at which point there is no further current media time.
+ */
+ void onStop();
+ }
+}
+
diff --git a/media/src/main/java/androidx/media/subtitle/SubtitleController.java b/media/src/main/java/androidx/media/subtitle/SubtitleController.java
new file mode 100644
index 0000000..b6dfc2b
--- /dev/null
+++ b/media/src/main/java/androidx/media/subtitle/SubtitleController.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.subtitle;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.media.MediaFormat;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.TrackInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.view.accessibility.CaptioningManager;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.media.subtitle.SubtitleTrack.RenderingWidget;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+// Note: This is forked from android.media.SubtitleController since P
+/**
+ * The subtitle controller provides the architecture to display subtitles for a
+ * media source. It allows specifying which tracks to display, on which anchor
+ * to display them, and also allows adding external, out-of-band subtitle tracks.
+ *
+ * @hide
+ */
+@RequiresApi(28)
+@RestrictTo(LIBRARY_GROUP)
+public class SubtitleController {
+ private MediaTimeProvider mTimeProvider;
+ private ArrayList<Renderer> mRenderers;
+ private ArrayList<SubtitleTrack> mTracks;
+ private final Object mRenderersLock = new Object();
+ private final Object mTracksLock = new Object();
+ private SubtitleTrack mSelectedTrack;
+ private boolean mShowing;
+ private CaptioningManager mCaptioningManager;
+ private Handler mHandler;
+
+ private static final int WHAT_SHOW = 1;
+ private static final int WHAT_HIDE = 2;
+ private static final int WHAT_SELECT_TRACK = 3;
+ private static final int WHAT_SELECT_DEFAULT_TRACK = 4;
+
+ private final Handler.Callback mCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case WHAT_SHOW:
+ doShow();
+ return true;
+ case WHAT_HIDE:
+ doHide();
+ return true;
+ case WHAT_SELECT_TRACK:
+ doSelectTrack((SubtitleTrack) msg.obj);
+ return true;
+ case WHAT_SELECT_DEFAULT_TRACK:
+ doSelectDefaultTrack();
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+
+ private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
+ new CaptioningManager.CaptioningChangeListener() {
+ @Override
+ public void onEnabledChanged(boolean enabled) {
+ selectDefaultTrack();
+ }
+
+ @Override
+ public void onLocaleChanged(Locale locale) {
+ selectDefaultTrack();
+ }
+ };
+
+ public SubtitleController(Context context) {
+ this(context, null, null);
+ }
+
+ /**
+ * Creates a subtitle controller for a media playback object that implements
+ * the MediaTimeProvider interface.
+ *
+ * @param timeProvider
+ */
+ public SubtitleController(
+ Context context,
+ MediaTimeProvider timeProvider,
+ Listener listener) {
+ mTimeProvider = timeProvider;
+ mListener = listener;
+
+ mRenderers = new ArrayList<Renderer>();
+ mShowing = false;
+ mTracks = new ArrayList<SubtitleTrack>();
+ mCaptioningManager =
+ (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ mCaptioningManager.removeCaptioningChangeListener(
+ mCaptioningChangeListener);
+ super.finalize();
+ }
+
+ /**
+ * @return the available subtitle tracks for this media. These include
+ * the tracks found by {@link MediaPlayer} as well as any tracks added
+ * manually via {@link #addTrack}.
+ */
+ public SubtitleTrack[] getTracks() {
+ synchronized (mTracksLock) {
+ SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
+ mTracks.toArray(tracks);
+ return tracks;
+ }
+ }
+
+ /**
+ * @return the currently selected subtitle track
+ */
+ public SubtitleTrack getSelectedTrack() {
+ return mSelectedTrack;
+ }
+
+ private RenderingWidget getRenderingWidget() {
+ if (mSelectedTrack == null) {
+ return null;
+ }
+ return mSelectedTrack.getRenderingWidget();
+ }
+
+ /**
+ * Selects a subtitle track. As a result, this track will receive
+ * in-band data from the {@link MediaPlayer}. However, this does
+ * not change the subtitle visibility.
+ *
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+ *
+ * @param track The subtitle track to select. This must be one of the
+ * tracks in {@link #getTracks}.
+ * @return true if the track was successfully selected.
+ */
+ public boolean selectTrack(SubtitleTrack track) {
+ if (track != null && !mTracks.contains(track)) {
+ return false;
+ }
+
+ processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_TRACK, track));
+ return true;
+ }
+
+ private void doSelectTrack(SubtitleTrack track) {
+ mTrackIsExplicit = true;
+ if (mSelectedTrack == track) {
+ return;
+ }
+
+ if (mSelectedTrack != null) {
+ mSelectedTrack.hide();
+ mSelectedTrack.setTimeProvider(null);
+ }
+
+ mSelectedTrack = track;
+ if (mAnchor != null) {
+ mAnchor.setSubtitleWidget(getRenderingWidget());
+ }
+
+ if (mSelectedTrack != null) {
+ mSelectedTrack.setTimeProvider(mTimeProvider);
+ mSelectedTrack.show();
+ }
+
+ if (mListener != null) {
+ mListener.onSubtitleTrackSelected(track);
+ }
+ }
+
+ /**
+ * @return the default subtitle track based on system preferences, or null,
+ * if no such track exists in this manager.
+ *
+ * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
+ *
+ * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
+ * consider all tracks, but prefer non-FORCED ones.
+ * 2. If user selected "Default" caption language:
+ * a. If there is a considered track with DEFAULT=yes, returns that track
+ * (favor the first one in the current language if there are more than
+ * one default tracks, or the first in general if none of them are in
+ * the current language).
+ * b. Otherwise, if there is a track with AUTOSELECT=yes in the current
+ * language, return that one.
+ * c. If there are no default tracks, and no autoselectable tracks in the
+ * current language, return null.
+ * 3. If there is a track with the caption language, select that one. Prefer
+ * the one with AUTOSELECT=no.
+ *
+ * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
+ * and FORCED=no.
+ */
+ public SubtitleTrack getDefaultTrack() {
+ SubtitleTrack bestTrack = null;
+ int bestScore = -1;
+
+ Locale selectedLocale = mCaptioningManager.getLocale();
+ Locale locale = selectedLocale;
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ boolean selectForced = !mCaptioningManager.isEnabled();
+
+ synchronized (mTracksLock) {
+ for (SubtitleTrack track: mTracks) {
+ MediaFormat format = track.getFormat();
+ String language = format.getString(MediaFormat.KEY_LANGUAGE);
+ boolean forced = MediaFormatUtil
+ .getInteger(format, MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
+ boolean autoselect = MediaFormatUtil
+ .getInteger(format, MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
+ boolean is_default = MediaFormatUtil
+ .getInteger(format, MediaFormat.KEY_IS_DEFAULT, 0) != 0;
+
+ boolean languageMatches = locale == null
+ || locale.getLanguage().equals("")
+ || locale.getISO3Language().equals(language)
+ || locale.getLanguage().equals(language);
+ // is_default is meaningless unless caption language is 'default'
+ int score = (forced ? 0 : 8)
+ + (((selectedLocale == null) && is_default) ? 4 : 0)
+ + (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
+
+ if (selectForced && !forced) {
+ continue;
+ }
+
+ // we treat null locale/language as matching any language
+ if ((selectedLocale == null && is_default)
+ || (languageMatches && (autoselect || forced || selectedLocale != null))) {
+ if (score > bestScore) {
+ bestScore = score;
+ bestTrack = track;
+ }
+ }
+ }
+ }
+ return bestTrack;
+ }
+
+ static class MediaFormatUtil {
+ MediaFormatUtil() { }
+ static int getInteger(MediaFormat format, String name, int defaultValue) {
+ try {
+ return format.getInteger(name);
+ } catch (NullPointerException | ClassCastException e) {
+ /* no such field or field of different type */
+ }
+ return defaultValue;
+ }
+ }
+
+ private boolean mTrackIsExplicit = false;
+ private boolean mVisibilityIsExplicit = false;
+
+ /** should be called from anchor thread */
+ public void selectDefaultTrack() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_DEFAULT_TRACK));
+ }
+
+ private void doSelectDefaultTrack() {
+ if (mTrackIsExplicit) {
+ if (mVisibilityIsExplicit) {
+ return;
+ }
+ // If track selection is explicit, but visibility
+ // is not, it falls back to the captioning setting
+ if (mCaptioningManager.isEnabled()
+ || (mSelectedTrack != null && MediaFormatUtil.getInteger(
+ mSelectedTrack.getFormat(),
+ MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
+ show();
+ } else if (mSelectedTrack != null
+ && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ hide();
+ }
+ mVisibilityIsExplicit = false;
+ }
+
+ // We can have a default (forced) track even if captioning
+ // is not enabled. This is handled by getDefaultTrack().
+ // Show this track unless subtitles were explicitly hidden.
+ SubtitleTrack track = getDefaultTrack();
+ if (track != null) {
+ selectTrack(track);
+ mTrackIsExplicit = false;
+ if (!mVisibilityIsExplicit) {
+ show();
+ mVisibilityIsExplicit = false;
+ }
+ }
+ }
+
+ /** must be called from anchor thread */
+ public void reset() {
+ checkAnchorLooper();
+ hide();
+ selectTrack(null);
+ mTracks.clear();
+ mTrackIsExplicit = false;
+ mVisibilityIsExplicit = false;
+ mCaptioningManager.removeCaptioningChangeListener(
+ mCaptioningChangeListener);
+ }
+
+ /**
+ * Adds a new, external subtitle track to the manager.
+ *
+ * @param format the format of the track that will include at least
+ * the MIME type {@link MediaFormat@KEY_MIME}.
+ * @return the created {@link SubtitleTrack} object
+ */
+ public SubtitleTrack addTrack(MediaFormat format) {
+ synchronized (mRenderersLock) {
+ for (Renderer renderer: mRenderers) {
+ if (renderer.supports(format)) {
+ SubtitleTrack track = renderer.createTrack(format);
+ if (track != null) {
+ synchronized (mTracksLock) {
+ if (mTracks.size() == 0) {
+ mCaptioningManager.addCaptioningChangeListener(
+ mCaptioningChangeListener);
+ }
+ mTracks.add(track);
+ }
+ return track;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Show the selected (or default) subtitle track.
+ *
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+ */
+ public void show() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_SHOW));
+ }
+
+ private void doShow() {
+ mShowing = true;
+ mVisibilityIsExplicit = true;
+ if (mSelectedTrack != null) {
+ mSelectedTrack.show();
+ }
+ }
+
+ /**
+ * Hide the selected (or default) subtitle track.
+ *
+ * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
+ */
+ public void hide() {
+ processOnAnchor(mHandler.obtainMessage(WHAT_HIDE));
+ }
+
+ private void doHide() {
+ mVisibilityIsExplicit = true;
+ if (mSelectedTrack != null) {
+ mSelectedTrack.hide();
+ }
+ mShowing = false;
+ }
+
+ /**
+ * Interface for supporting a single or multiple subtitle types in {@link MediaPlayer}.
+ */
+ public abstract static class Renderer {
+ /**
+ * Called by {@link MediaPlayer}'s {@link SubtitleController} when a new
+ * subtitle track is detected, to see if it should use this object to
+ * parse and display this subtitle track.
+ *
+ * @param format the format of the track that will include at least
+ * the MIME type {@link MediaFormat@KEY_MIME}.
+ *
+ * @return true if and only if the track format is supported by this
+ * renderer
+ */
+ public abstract boolean supports(MediaFormat format);
+
+ /**
+ * Called by {@link MediaPlayer}'s {@link SubtitleController} for each
+ * subtitle track that was detected and is supported by this object to
+ * create a {@link SubtitleTrack} object. This object will be created
+ * for each track that was found. If the track is selected for display,
+ * this object will be used to parse and display the track data.
+ *
+ * @param format the format of the track that will include at least
+ * the MIME type {@link MediaFormat@KEY_MIME}.
+ * @return a {@link SubtitleTrack} object that will be used to parse
+ * and render the subtitle track.
+ */
+ public abstract SubtitleTrack createTrack(MediaFormat format);
+ }
+
+ /**
+ * Add support for a subtitle format in {@link MediaPlayer}.
+ *
+ * @param renderer a {@link SubtitleController.Renderer} object that adds
+ * support for a subtitle format.
+ */
+ public void registerRenderer(Renderer renderer) {
+ synchronized (mRenderersLock) {
+ // TODO how to get available renderers in the system
+ if (!mRenderers.contains(renderer)) {
+ // TODO should added renderers override existing ones (to allow replacing?)
+ mRenderers.add(renderer);
+ }
+ }
+ }
+
+ /**
+ * Returns true if one of the registered renders supports given media format.
+ *
+ * @param format a {@link MediaFormat} object
+ * @return true if this SubtitleController has a renderer that supports
+ * the media format.
+ */
+ public boolean hasRendererFor(MediaFormat format) {
+ synchronized (mRenderersLock) {
+ // TODO how to get available renderers in the system
+ for (Renderer renderer: mRenderers) {
+ if (renderer.supports(format)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Subtitle anchor, an object that is able to display a subtitle renderer,
+ * e.g. a VideoView.
+ */
+ public interface Anchor {
+ /**
+ * Anchor should use the supplied subtitle rendering widget, or
+ * none if it is null.
+ */
+ void setSubtitleWidget(RenderingWidget subtitleWidget);
+
+ /**
+ * Anchors provide the looper on which all track visibility changes
+ * (track.show/hide, setSubtitleWidget) will take place.
+ */
+ Looper getSubtitleLooper();
+ }
+
+ private Anchor mAnchor;
+
+ /**
+ * called from anchor's looper (if any, both when unsetting and
+ * setting)
+ */
+ public void setAnchor(Anchor anchor) {
+ if (mAnchor == anchor) {
+ return;
+ }
+
+ if (mAnchor != null) {
+ checkAnchorLooper();
+ mAnchor.setSubtitleWidget(null);
+ }
+ mAnchor = anchor;
+ mHandler = null;
+ if (mAnchor != null) {
+ mHandler = new Handler(mAnchor.getSubtitleLooper(), mCallback);
+ checkAnchorLooper();
+ mAnchor.setSubtitleWidget(getRenderingWidget());
+ }
+ }
+
+ private void checkAnchorLooper() {
+ assert mHandler != null : "Should have a looper already";
+ assert Looper.myLooper() == mHandler.getLooper()
+ : "Must be called from the anchor's looper";
+ }
+
+ private void processOnAnchor(Message m) {
+ assert mHandler != null : "Should have a looper already";
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ mHandler.dispatchMessage(m);
+ } else {
+ mHandler.sendMessage(m);
+ }
+ }
+
+ interface Listener {
+ /**
+ * Called when a subtitle track has been selected.
+ *
+ * @param track selected subtitle track or null
+ */
+ void onSubtitleTrackSelected(SubtitleTrack track);
+ }
+
+ private Listener mListener;
+}
diff --git a/media/src/main/java/androidx/media/subtitle/SubtitleTrack.java b/media/src/main/java/androidx/media/subtitle/SubtitleTrack.java
new file mode 100644
index 0000000..30c1316
--- /dev/null
+++ b/media/src/main/java/androidx/media/subtitle/SubtitleTrack.java
@@ -0,0 +1,715 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.subtitle;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Canvas;
+import android.media.MediaFormat;
+import android.media.MediaPlayer.TrackInfo;
+import android.media.SubtitleData;
+import android.os.Handler;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Pair;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+// Note: This is forked from android.media.SubtitleTrack since P
+/**
+ * A subtitle track abstract base class that is responsible for parsing and displaying
+ * an instance of a particular type of subtitle.
+ *
+ * @hide
+ */
+@RequiresApi(28)
+@RestrictTo(LIBRARY_GROUP)
+public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeListener {
+ private static final String TAG = "SubtitleTrack";
+ private long mLastUpdateTimeMs;
+ private long mLastTimeMs;
+
+ private Runnable mRunnable;
+
+ private final LongSparseArray<Run> mRunsByEndTime = new LongSparseArray<Run>();
+ private final LongSparseArray<Run> mRunsByID = new LongSparseArray<Run>();
+
+ private CueList mCues;
+ private final ArrayList<Cue> mActiveCues = new ArrayList<Cue>();
+ protected boolean mVisible;
+
+ public boolean DEBUG = false;
+
+ protected Handler mHandler = new Handler();
+
+ private MediaFormat mFormat;
+
+ public SubtitleTrack(MediaFormat format) {
+ mFormat = format;
+ mCues = new CueList();
+ clearActiveCues();
+ mLastTimeMs = -1;
+ }
+
+ public final MediaFormat getFormat() {
+ return mFormat;
+ }
+
+ private long mNextScheduledTimeMs = -1;
+
+ /**
+ * Called when there is input data for the subtitle track.
+ */
+ public void onData(SubtitleData data) {
+ long runID = data.getStartTimeUs() + 1;
+ onData(data.getData(), true /* eos */, runID);
+ setRunDiscardTimeMs(
+ runID,
+ (data.getStartTimeUs() + data.getDurationUs()) / 1000);
+ }
+
+ /**
+ * Called when there is input data for the subtitle track. The
+ * complete subtitle for a track can include multiple whole units
+ * (runs). Each of these units can have multiple sections. The
+ * contents of a run are submitted in sequential order, with eos
+ * indicating the last section of the run. Calls from different
+ * runs must not be intermixed.
+ *
+ * @param data subtitle data byte buffer
+ * @param eos true if this is the last section of the run.
+ * @param runID mostly-unique ID for this run of data. Subtitle cues
+ * with runID of 0 are discarded immediately after
+ * display. Cues with runID of ~0 are discarded
+ * only at the deletion of the track object. Cues
+ * with other runID-s are discarded at the end of the
+ * run, which defaults to the latest timestamp of
+ * any of its cues (with this runID).
+ */
+ protected abstract void onData(byte[] data, boolean eos, long runID);
+
+ /**
+ * Called when adding the subtitle rendering widget to the view hierarchy,
+ * as well as when showing or hiding the subtitle track, or when the video
+ * surface position has changed.
+ *
+ * @return the widget that renders this subtitle track. For most renderers
+ * there should be a single shared instance that is used for all
+ * tracks supported by that renderer, as at most one subtitle track
+ * is visible at one time.
+ */
+ public abstract RenderingWidget getRenderingWidget();
+
+ /**
+ * Called when the active cues have changed, and the contents of the subtitle
+ * view should be updated.
+ */
+ public abstract void updateView(ArrayList<Cue> activeCues);
+
+ protected synchronized void updateActiveCues(boolean rebuild, long timeMs) {
+ // out-of-order times mean seeking or new active cues being added
+ // (during their own timespan)
+ if (rebuild || mLastUpdateTimeMs > timeMs) {
+ clearActiveCues();
+ }
+
+ for (Iterator<Pair<Long, Cue>> it =
+ mCues.entriesBetween(mLastUpdateTimeMs, timeMs).iterator(); it.hasNext(); ) {
+ Pair<Long, Cue> event = it.next();
+ Cue cue = event.second;
+
+ if (cue.mEndTimeMs == event.first) {
+ // remove past cues
+ if (DEBUG) Log.v(TAG, "Removing " + cue);
+ mActiveCues.remove(cue);
+ if (cue.mRunID == 0) {
+ it.remove();
+ }
+ } else if (cue.mStartTimeMs == event.first) {
+ // add new cues
+ // TRICKY: this will happen in start order
+ if (DEBUG) Log.v(TAG, "Adding " + cue);
+ if (cue.mInnerTimesMs != null) {
+ cue.onTime(timeMs);
+ }
+ mActiveCues.add(cue);
+ } else if (cue.mInnerTimesMs != null) {
+ // cue is modified
+ cue.onTime(timeMs);
+ }
+ }
+
+ /* complete any runs */
+ while (mRunsByEndTime.size() > 0 && mRunsByEndTime.keyAt(0) <= timeMs) {
+ removeRunsByEndTimeIndex(0); // removes element
+ }
+ mLastUpdateTimeMs = timeMs;
+ }
+
+ private void removeRunsByEndTimeIndex(int ix) {
+ Run run = mRunsByEndTime.valueAt(ix);
+ while (run != null) {
+ Cue cue = run.mFirstCue;
+ while (cue != null) {
+ mCues.remove(cue);
+ Cue nextCue = cue.mNextInRun;
+ cue.mNextInRun = null;
+ cue = nextCue;
+ }
+ mRunsByID.remove(run.mRunID);
+ Run nextRun = run.mNextRunAtEndTimeMs;
+ run.mPrevRunAtEndTimeMs = null;
+ run.mNextRunAtEndTimeMs = null;
+ run = nextRun;
+ }
+ mRunsByEndTime.removeAt(ix);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ /* remove all cues (untangle all cross-links) */
+ int size = mRunsByEndTime.size();
+ for (int ix = size - 1; ix >= 0; ix--) {
+ removeRunsByEndTimeIndex(ix);
+ }
+
+ super.finalize();
+ }
+
+ private synchronized void takeTime(long timeMs) {
+ mLastTimeMs = timeMs;
+ }
+
+ protected synchronized void clearActiveCues() {
+ if (DEBUG) Log.v(TAG, "Clearing " + mActiveCues.size() + " active cues");
+ mActiveCues.clear();
+ mLastUpdateTimeMs = -1;
+ }
+
+ protected void scheduleTimedEvents() {
+ /* get times for the next event */
+ if (mTimeProvider != null) {
+ mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
+ if (DEBUG) Log.d(TAG, "sched @" + mNextScheduledTimeMs + " after " + mLastTimeMs);
+ mTimeProvider.notifyAt(mNextScheduledTimeMs >= 0
+ ? (mNextScheduledTimeMs * 1000) : MediaTimeProvider.NO_TIME, this);
+ }
+ }
+
+ @Override
+ public void onTimedEvent(long timeUs) {
+ if (DEBUG) Log.d(TAG, "onTimedEvent " + timeUs);
+ synchronized (this) {
+ long timeMs = timeUs / 1000;
+ updateActiveCues(false, timeMs);
+ takeTime(timeMs);
+ }
+ updateView(mActiveCues);
+ scheduleTimedEvents();
+ }
+
+ @Override
+ public void onSeek(long timeUs) {
+ if (DEBUG) Log.d(TAG, "onSeek " + timeUs);
+ synchronized (this) {
+ long timeMs = timeUs / 1000;
+ updateActiveCues(true, timeMs);
+ takeTime(timeMs);
+ }
+ updateView(mActiveCues);
+ scheduleTimedEvents();
+ }
+
+ @Override
+ public void onStop() {
+ synchronized (this) {
+ if (DEBUG) Log.d(TAG, "onStop");
+ clearActiveCues();
+ mLastTimeMs = -1;
+ }
+ updateView(mActiveCues);
+ mNextScheduledTimeMs = -1;
+ mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+ }
+
+ protected MediaTimeProvider mTimeProvider;
+
+ /**
+ * Shows subtitle rendering widget
+ */
+ public void show() {
+ if (mVisible) {
+ return;
+ }
+
+ mVisible = true;
+ RenderingWidget renderingWidget = getRenderingWidget();
+ if (renderingWidget != null) {
+ renderingWidget.setVisible(true);
+ }
+ if (mTimeProvider != null) {
+ mTimeProvider.scheduleUpdate(this);
+ }
+ }
+
+ /**
+ * Hides subtitle rendering widget
+ */
+ public void hide() {
+ if (!mVisible) {
+ return;
+ }
+
+ if (mTimeProvider != null) {
+ mTimeProvider.cancelNotifications(this);
+ }
+ RenderingWidget renderingWidget = getRenderingWidget();
+ if (renderingWidget != null) {
+ renderingWidget.setVisible(false);
+ }
+ mVisible = false;
+ }
+
+ protected synchronized boolean addCue(Cue cue) {
+ mCues.add(cue);
+
+ if (cue.mRunID != 0) {
+ Run run = mRunsByID.get(cue.mRunID);
+ if (run == null) {
+ run = new Run();
+ mRunsByID.put(cue.mRunID, run);
+ run.mEndTimeMs = cue.mEndTimeMs;
+ } else if (run.mEndTimeMs < cue.mEndTimeMs) {
+ run.mEndTimeMs = cue.mEndTimeMs;
+ }
+
+ // link-up cues in the same run
+ cue.mNextInRun = run.mFirstCue;
+ run.mFirstCue = cue;
+ }
+
+ // if a cue is added that should be visible, need to refresh view
+ long nowMs = -1;
+ if (mTimeProvider != null) {
+ try {
+ nowMs = mTimeProvider.getCurrentTimeUs(
+ false /* precise */, true /* monotonic */) / 1000;
+ } catch (IllegalStateException e) {
+ // handle as it we are not playing
+ }
+ }
+
+ if (DEBUG) {
+ Log.v(TAG, "mVisible=" + mVisible + ", "
+ + cue.mStartTimeMs + " <= " + nowMs + ", "
+ + cue.mEndTimeMs + " >= " + mLastTimeMs);
+ }
+
+ if (mVisible && cue.mStartTimeMs <= nowMs
+ // we don't trust nowMs, so check any cue since last callback
+ && cue.mEndTimeMs >= mLastTimeMs) {
+ if (mRunnable != null) {
+ mHandler.removeCallbacks(mRunnable);
+ }
+ final SubtitleTrack track = this;
+ final long thenMs = nowMs;
+ mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // even with synchronized, it is possible that we are going
+ // to do multiple updates as the runnable could be already
+ // running.
+ synchronized (track) {
+ mRunnable = null;
+ updateActiveCues(true, thenMs);
+ updateView(mActiveCues);
+ }
+ }
+ };
+ // delay update so we don't update view on every cue. TODO why 10?
+ if (mHandler.postDelayed(mRunnable, 10 /* delay */)) {
+ if (DEBUG) Log.v(TAG, "scheduling update");
+ } else {
+ if (DEBUG) Log.w(TAG, "failed to schedule subtitle view update");
+ }
+ return true;
+ }
+
+ if (mVisible && cue.mEndTimeMs >= mLastTimeMs
+ && (cue.mStartTimeMs < mNextScheduledTimeMs || mNextScheduledTimeMs < 0)) {
+ scheduleTimedEvents();
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets MediaTimeProvider
+ */
+ public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
+ if (mTimeProvider == timeProvider) {
+ return;
+ }
+ if (mTimeProvider != null) {
+ mTimeProvider.cancelNotifications(this);
+ }
+ mTimeProvider = timeProvider;
+ if (mTimeProvider != null) {
+ mTimeProvider.scheduleUpdate(this);
+ }
+ }
+
+
+ static class CueList {
+ private static final String TAG = "CueList";
+ // simplistic, inefficient implementation
+ private SortedMap<Long, ArrayList<Cue>> mCues;
+ public boolean DEBUG = false;
+
+ private boolean addEvent(Cue cue, long timeMs) {
+ ArrayList<Cue> cues = mCues.get(timeMs);
+ if (cues == null) {
+ cues = new ArrayList<Cue>(2);
+ mCues.put(timeMs, cues);
+ } else if (cues.contains(cue)) {
+ // do not duplicate cues
+ return false;
+ }
+
+ cues.add(cue);
+ return true;
+ }
+
+ private void removeEvent(Cue cue, long timeMs) {
+ ArrayList<Cue> cues = mCues.get(timeMs);
+ if (cues != null) {
+ cues.remove(cue);
+ if (cues.size() == 0) {
+ mCues.remove(timeMs);
+ }
+ }
+ }
+
+ public void add(Cue cue) {
+ // ignore non-positive-duration cues
+ if (cue.mStartTimeMs >= cue.mEndTimeMs) return;
+
+ if (!addEvent(cue, cue.mStartTimeMs)) {
+ return;
+ }
+
+ long lastTimeMs = cue.mStartTimeMs;
+ if (cue.mInnerTimesMs != null) {
+ for (long timeMs: cue.mInnerTimesMs) {
+ if (timeMs > lastTimeMs && timeMs < cue.mEndTimeMs) {
+ addEvent(cue, timeMs);
+ lastTimeMs = timeMs;
+ }
+ }
+ }
+
+ addEvent(cue, cue.mEndTimeMs);
+ }
+
+ public void remove(Cue cue) {
+ removeEvent(cue, cue.mStartTimeMs);
+ if (cue.mInnerTimesMs != null) {
+ for (long timeMs: cue.mInnerTimesMs) {
+ removeEvent(cue, timeMs);
+ }
+ }
+ removeEvent(cue, cue.mEndTimeMs);
+ }
+
+ public Iterable<Pair<Long, Cue>> entriesBetween(
+ final long lastTimeMs, final long timeMs) {
+ return new Iterable<Pair<Long, Cue>>() {
+ @Override
+ public Iterator<Pair<Long, Cue>> iterator() {
+ if (DEBUG) Log.d(TAG, "slice (" + lastTimeMs + ", " + timeMs + "]=");
+ try {
+ return new EntryIterator(
+ mCues.subMap(lastTimeMs + 1, timeMs + 1));
+ } catch (IllegalArgumentException e) {
+ return new EntryIterator(null);
+ }
+ }
+ };
+ }
+
+ public long nextTimeAfter(long timeMs) {
+ SortedMap<Long, ArrayList<Cue>> tail = null;
+ try {
+ tail = mCues.tailMap(timeMs + 1);
+ if (tail != null) {
+ return tail.firstKey();
+ } else {
+ return -1;
+ }
+ } catch (IllegalArgumentException e) {
+ return -1;
+ } catch (NoSuchElementException e) {
+ return -1;
+ }
+ }
+
+ class EntryIterator implements Iterator<Pair<Long, Cue>> {
+ @Override
+ public boolean hasNext() {
+ return !mDone;
+ }
+
+ @Override
+ public Pair<Long, Cue> next() {
+ if (mDone) {
+ throw new NoSuchElementException("");
+ }
+ mLastEntry = new Pair<Long, Cue>(
+ mCurrentTimeMs, mListIterator.next());
+ mLastListIterator = mListIterator;
+ if (!mListIterator.hasNext()) {
+ nextKey();
+ }
+ return mLastEntry;
+ }
+
+ @Override
+ public void remove() {
+ // only allow removing end tags
+ if (mLastListIterator == null
+ || mLastEntry.second.mEndTimeMs != mLastEntry.first) {
+ throw new IllegalStateException("");
+ }
+
+ // remove end-cue
+ mLastListIterator.remove();
+ mLastListIterator = null;
+ if (mCues.get(mLastEntry.first).size() == 0) {
+ mCues.remove(mLastEntry.first);
+ }
+
+ // remove rest of the cues
+ Cue cue = mLastEntry.second;
+ removeEvent(cue, cue.mStartTimeMs);
+ if (cue.mInnerTimesMs != null) {
+ for (long timeMs: cue.mInnerTimesMs) {
+ removeEvent(cue, timeMs);
+ }
+ }
+ }
+
+ EntryIterator(SortedMap<Long, ArrayList<Cue>> cues) {
+ if (DEBUG) Log.v(TAG, cues + "");
+ mRemainingCues = cues;
+ mLastListIterator = null;
+ nextKey();
+ }
+
+ private void nextKey() {
+ do {
+ try {
+ if (mRemainingCues == null) {
+ throw new NoSuchElementException("");
+ }
+ mCurrentTimeMs = mRemainingCues.firstKey();
+ mListIterator =
+ mRemainingCues.get(mCurrentTimeMs).iterator();
+ try {
+ mRemainingCues =
+ mRemainingCues.tailMap(mCurrentTimeMs + 1);
+ } catch (IllegalArgumentException e) {
+ mRemainingCues = null;
+ }
+ mDone = false;
+ } catch (NoSuchElementException e) {
+ mDone = true;
+ mRemainingCues = null;
+ mListIterator = null;
+ return;
+ }
+ } while (!mListIterator.hasNext());
+ }
+
+ private long mCurrentTimeMs;
+ private Iterator<Cue> mListIterator;
+ private boolean mDone;
+ private SortedMap<Long, ArrayList<Cue>> mRemainingCues;
+ private Iterator<Cue> mLastListIterator;
+ private Pair<Long, Cue> mLastEntry;
+ }
+
+ CueList() {
+ mCues = new TreeMap<Long, ArrayList<Cue>>();
+ }
+ }
+
+ static class Cue {
+ public long mStartTimeMs;
+ public long mEndTimeMs;
+ public long[] mInnerTimesMs;
+ public long mRunID;
+
+ public Cue mNextInRun;
+
+ /**
+ * Called to inform current timeMs to the cue
+ */
+ public void onTime(long timeMs) { }
+ }
+
+ /** update mRunsByEndTime (with default end time) */
+ protected void finishedRun(long runID) {
+ if (runID != 0 && runID != ~0) {
+ Run run = mRunsByID.get(runID);
+ if (run != null) {
+ run.storeByEndTimeMs(mRunsByEndTime);
+ }
+ }
+ }
+
+ /** update mRunsByEndTime with given end time */
+ public void setRunDiscardTimeMs(long runID, long timeMs) {
+ if (runID != 0 && runID != ~0) {
+ Run run = mRunsByID.get(runID);
+ if (run != null) {
+ run.mEndTimeMs = timeMs;
+ run.storeByEndTimeMs(mRunsByEndTime);
+ }
+ }
+ }
+
+ /** whether this is a text track who fires events instead getting rendered */
+ public int getTrackType() {
+ return getRenderingWidget() == null
+ ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
+ : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
+ }
+
+
+ private static class Run {
+ public Cue mFirstCue;
+ public Run mNextRunAtEndTimeMs;
+ public Run mPrevRunAtEndTimeMs;
+ public long mEndTimeMs = -1;
+ public long mRunID = 0;
+ private long mStoredEndTimeMs = -1;
+
+ public void storeByEndTimeMs(LongSparseArray<Run> runsByEndTime) {
+ // remove old value if any
+ int ix = runsByEndTime.indexOfKey(mStoredEndTimeMs);
+ if (ix >= 0) {
+ if (mPrevRunAtEndTimeMs == null) {
+ assert (this == runsByEndTime.valueAt(ix));
+ if (mNextRunAtEndTimeMs == null) {
+ runsByEndTime.removeAt(ix);
+ } else {
+ runsByEndTime.setValueAt(ix, mNextRunAtEndTimeMs);
+ }
+ }
+ removeAtEndTimeMs();
+ }
+
+ // add new value
+ if (mEndTimeMs >= 0) {
+ mPrevRunAtEndTimeMs = null;
+ mNextRunAtEndTimeMs = runsByEndTime.get(mEndTimeMs);
+ if (mNextRunAtEndTimeMs != null) {
+ mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = this;
+ }
+ runsByEndTime.put(mEndTimeMs, this);
+ mStoredEndTimeMs = mEndTimeMs;
+ }
+ }
+
+ public void removeAtEndTimeMs() {
+ Run prev = mPrevRunAtEndTimeMs;
+
+ if (mPrevRunAtEndTimeMs != null) {
+ mPrevRunAtEndTimeMs.mNextRunAtEndTimeMs = mNextRunAtEndTimeMs;
+ mPrevRunAtEndTimeMs = null;
+ }
+ if (mNextRunAtEndTimeMs != null) {
+ mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = prev;
+ mNextRunAtEndTimeMs = null;
+ }
+ }
+ }
+
+ /**
+ * Interface for rendering subtitles onto a Canvas.
+ */
+ public interface RenderingWidget {
+ /**
+ * Sets the widget's callback, which is used to send updates when the
+ * rendered data has changed.
+ *
+ * @param callback update callback
+ */
+ void setOnChangedListener(OnChangedListener callback);
+
+ /**
+ * Sets the widget's size.
+ *
+ * @param width width in pixels
+ * @param height height in pixels
+ */
+ void setSize(int width, int height);
+
+ /**
+ * Sets whether the widget should draw subtitles.
+ *
+ * @param visible true if subtitles should be drawn, false otherwise
+ */
+ void setVisible(boolean visible);
+
+ /**
+ * Renders subtitles onto a {@link Canvas}.
+ *
+ * @param c canvas on which to render subtitles
+ */
+ void draw(Canvas c);
+
+ /**
+ * Called when the widget is attached to a window.
+ */
+ void onAttachedToWindow();
+
+ /**
+ * Called when the widget is detached from a window.
+ */
+ void onDetachedFromWindow();
+
+ /**
+ * Callback used to send updates about changes to rendering data.
+ */
+ public interface OnChangedListener {
+ /**
+ * Called when the rendering data has changed.
+ *
+ * @param renderingWidget the widget whose data has changed
+ */
+ void onChanged(RenderingWidget renderingWidget);
+ }
+ }
+}
diff --git a/media/src/main/res/values/dimens.xml b/media/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..be50378
--- /dev/null
+++ b/media/src/main/res/values/dimens.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- Shadow radius for video subtitles. -->
+ <dimen name="subtitle_shadow_radius">2dp</dimen>
+
+ <!-- Shadow offset for video subtitles. -->
+ <dimen name="subtitle_shadow_offset">2dp</dimen>
+
+ <!-- Outline width for video subtitles. -->
+ <dimen name="subtitle_outline_width">2dp</dimen>
+</resources>
diff --git a/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index 3519f2f..8e5b944 100644
--- a/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -55,6 +55,7 @@
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_SESSION_TAG;
import static android.support.mediacompat.testlib.MediaSessionConstants.TEST_VALUE;
import static android.support.mediacompat.testlib.VersionConstants.KEY_CLIENT_VERSION;
+import static android.support.mediacompat.testlib.util.IntentUtil.CLIENT_RECEIVER_COMPONENT_NAME;
import static android.support.mediacompat.testlib.util.IntentUtil.callMediaControllerMethod;
import static android.support.mediacompat.testlib.util.IntentUtil.callTransportControlsMethod;
import static android.support.mediacompat.testlib.util.TestUtil.assertBundleEquals;
@@ -96,6 +97,7 @@
import android.util.Log;
import android.view.KeyEvent;
+import androidx.media.MediaSessionManager;
import androidx.media.VolumeProviderCompat;
import org.junit.After;
@@ -323,6 +325,12 @@
@Test
@SmallTest
+ public void testGetCurrentControllerInfo() {
+ assertNull(mSession.getCurrentControllerInfo());
+ }
+
+ @Test
+ @SmallTest
public void testSendCommand() throws Exception {
mCallback.reset(1);
@@ -339,6 +347,8 @@
assertNotNull(mCallback.mCommandCallback);
assertEquals(TEST_COMMAND, mCallback.mCommand);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
}
@Test
@@ -361,6 +371,8 @@
assertEquals(-1, mCallback.mQueueIndex);
assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
Bundle arguments = new Bundle();
@@ -374,6 +386,8 @@
assertEquals(0, mCallback.mQueueIndex);
assertEquals(TEST_MEDIA_ID_2, mCallback.mQueueDescription.getMediaId());
assertEquals(TEST_MEDIA_TITLE_2, mCallback.mQueueDescription.getTitle());
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callMediaControllerMethod(
@@ -382,6 +396,8 @@
assertTrue(mCallback.mOnRemoveQueueItemCalled);
assertEquals(TEST_MEDIA_ID_1, mCallback.mQueueDescription.getMediaId());
assertEquals(TEST_MEDIA_TITLE_1, mCallback.mQueueDescription.getTitle());
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
}
@Test
@@ -391,39 +407,53 @@
callTransportControlsMethod(PLAY, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertEquals(1, mCallback.mOnPlayCalledCount);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(PAUSE, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPauseCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(STOP, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnStopCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(
FAST_FORWARD, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnFastForwardCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(REWIND, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnRewindCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(
SKIP_TO_PREVIOUS, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSkipToPreviousCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(
SKIP_TO_NEXT, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSkipToNextCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final long seekPosition = 1000;
@@ -432,6 +462,8 @@
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSeekToCalled);
assertEquals(seekPosition, mCallback.mSeekPosition);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final RatingCompat rating =
@@ -442,6 +474,8 @@
assertTrue(mCallback.mOnSetRatingCalled);
assertEquals(rating.getRatingStyle(), mCallback.mRating.getRatingStyle());
assertEquals(rating.getStarRating(), mCallback.mRating.getStarRating(), DELTA);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final Bundle extras = new Bundle();
@@ -455,6 +489,8 @@
assertTrue(mCallback.mOnPlayFromMediaIdCalled);
assertEquals(TEST_MEDIA_ID_1, mCallback.mMediaId);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final String query = "test-query";
@@ -467,6 +503,8 @@
assertTrue(mCallback.mOnPlayFromSearchCalled);
assertEquals(query, mCallback.mQuery);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final Uri uri = Uri.parse("content://test/popcorn.mod");
@@ -479,6 +517,8 @@
assertTrue(mCallback.mOnPlayFromUriCalled);
assertEquals(uri, mCallback.mUri);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final String action = "test-action";
@@ -491,6 +531,8 @@
assertTrue(mCallback.mOnCustomActionCalled);
assertEquals(action, mCallback.mAction);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
mCallback.mOnCustomActionCalled = false;
@@ -510,6 +552,8 @@
assertTrue(mCallback.mOnCustomActionCalled);
assertEquals(action, mCallback.mAction);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final long queueItemId = 1000;
@@ -518,12 +562,16 @@
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSkipToQueueItemCalled);
assertEquals(queueItemId, mCallback.mQueueItemId);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(
PREPARE, null, getContext(), mSession.getSessionToken());
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnPrepareCalled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
arguments = new Bundle();
@@ -535,6 +583,8 @@
assertTrue(mCallback.mOnPrepareFromMediaIdCalled);
assertEquals(TEST_MEDIA_ID_2, mCallback.mMediaId);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
arguments = new Bundle();
@@ -546,6 +596,8 @@
assertTrue(mCallback.mOnPrepareFromSearchCalled);
assertEquals(query, mCallback.mQuery);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
arguments = new Bundle();
@@ -557,6 +609,8 @@
assertTrue(mCallback.mOnPrepareFromUriCalled);
assertEquals(uri, mCallback.mUri);
assertBundleEquals(extras, mCallback.mExtras);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
callTransportControlsMethod(
@@ -564,6 +618,8 @@
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetCaptioningEnabledCalled);
assertEquals(ENABLED, mCallback.mCaptioningEnabled);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final int repeatMode = PlaybackStateCompat.REPEAT_MODE_ALL;
@@ -572,6 +628,8 @@
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetRepeatModeCalled);
assertEquals(repeatMode, mCallback.mRepeatMode);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
final int shuffleMode = PlaybackStateCompat.SHUFFLE_MODE_ALL;
@@ -580,6 +638,8 @@
mCallback.await(TIME_OUT_MS);
assertTrue(mCallback.mOnSetShuffleModeCalled);
assertEquals(shuffleMode, mCallback.mShuffleMode);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
}
/**
@@ -605,6 +665,8 @@
sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PLAY);
assertTrue(mCallback.await(TIME_OUT_MS));
assertEquals(1, mCallback.mOnPlayCalledCount);
+ assertEquals(CLIENT_RECEIVER_COMPONENT_NAME.getPackageName(),
+ mCallback.mControllerInfo.getPackageName());
mCallback.reset(1);
sendMediaKeyInputToController(KeyEvent.KEYCODE_MEDIA_PAUSE);
@@ -825,6 +887,7 @@
private int mQueueIndex;
private MediaDescriptionCompat mQueueDescription;
private List<MediaSessionCompat.QueueItem> mQueue = new ArrayList<>();
+ private MediaSessionManager.RemoteUserInfo mControllerInfo;
private int mOnPlayCalledCount;
private boolean mOnPauseCalled;
@@ -869,6 +932,7 @@
mShuffleMode = PlaybackStateCompat.SHUFFLE_MODE_NONE;
mQueueIndex = -1;
mQueueDescription = null;
+ mControllerInfo = null;
mOnPlayCalledCount = 0;
mOnPauseCalled = false;
@@ -908,6 +972,7 @@
@Override
public void onPlay() {
mOnPlayCalledCount++;
+ mControllerInfo = mSession.getCurrentControllerInfo();
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
mLatch.countDown();
}
@@ -915,6 +980,7 @@
@Override
public void onPause() {
mOnPauseCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
mLatch.countDown();
}
@@ -922,6 +988,7 @@
@Override
public void onStop() {
mOnStopCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
setPlaybackState(PlaybackStateCompat.STATE_STOPPED);
mLatch.countDown();
}
@@ -929,30 +996,35 @@
@Override
public void onFastForward() {
mOnFastForwardCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mLatch.countDown();
}
@Override
public void onRewind() {
mOnRewindCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mLatch.countDown();
}
@Override
public void onSkipToPrevious() {
mOnSkipToPreviousCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mLatch.countDown();
}
@Override
public void onSkipToNext() {
mOnSkipToNextCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mLatch.countDown();
}
@Override
public void onSeekTo(long pos) {
mOnSeekToCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mSeekPosition = pos;
mLatch.countDown();
}
@@ -960,6 +1032,7 @@
@Override
public void onSetRating(RatingCompat rating) {
mOnSetRatingCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mRating = rating;
mLatch.countDown();
}
@@ -967,6 +1040,7 @@
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
mOnPlayFromMediaIdCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mMediaId = mediaId;
mExtras = extras;
mLatch.countDown();
@@ -975,6 +1049,7 @@
@Override
public void onPlayFromSearch(String query, Bundle extras) {
mOnPlayFromSearchCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mQuery = query;
mExtras = extras;
mLatch.countDown();
@@ -983,6 +1058,7 @@
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
mOnPlayFromUriCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mUri = uri;
mExtras = extras;
mLatch.countDown();
@@ -991,6 +1067,7 @@
@Override
public void onCustomAction(String action, Bundle extras) {
mOnCustomActionCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mAction = action;
mExtras = extras;
mLatch.countDown();
@@ -999,6 +1076,7 @@
@Override
public void onSkipToQueueItem(long id) {
mOnSkipToQueueItemCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mQueueItemId = id;
mLatch.countDown();
}
@@ -1006,6 +1084,7 @@
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
mOnCommandCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mCommand = command;
mExtras = extras;
mCommandCallback = cb;
@@ -1015,12 +1094,14 @@
@Override
public void onPrepare() {
mOnPrepareCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mLatch.countDown();
}
@Override
public void onPrepareFromMediaId(String mediaId, Bundle extras) {
mOnPrepareFromMediaIdCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mMediaId = mediaId;
mExtras = extras;
mLatch.countDown();
@@ -1029,6 +1110,7 @@
@Override
public void onPrepareFromSearch(String query, Bundle extras) {
mOnPrepareFromSearchCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mQuery = query;
mExtras = extras;
mLatch.countDown();
@@ -1037,6 +1119,7 @@
@Override
public void onPrepareFromUri(Uri uri, Bundle extras) {
mOnPrepareFromUriCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mUri = uri;
mExtras = extras;
mLatch.countDown();
@@ -1045,6 +1128,7 @@
@Override
public void onSetRepeatMode(int repeatMode) {
mOnSetRepeatModeCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mRepeatMode = repeatMode;
mLatch.countDown();
}
@@ -1052,6 +1136,7 @@
@Override
public void onAddQueueItem(MediaDescriptionCompat description) {
mOnAddQueueItemCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mQueueDescription = description;
mQueue.add(new MediaSessionCompat.QueueItem(description, mQueue.size()));
mSession.setQueue(mQueue);
@@ -1061,6 +1146,7 @@
@Override
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
mOnAddQueueItemAtCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mQueueIndex = index;
mQueueDescription = description;
mQueue.add(index, new MediaSessionCompat.QueueItem(description, mQueue.size()));
@@ -1071,6 +1157,7 @@
@Override
public void onRemoveQueueItem(MediaDescriptionCompat description) {
mOnRemoveQueueItemCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
String mediaId = description.getMediaId();
for (int i = mQueue.size() - 1; i >= 0; --i) {
if (mediaId.equals(mQueue.get(i).getDescription().getMediaId())) {
@@ -1085,6 +1172,7 @@
@Override
public void onSetCaptioningEnabled(boolean enabled) {
mOnSetCaptioningEnabledCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mCaptioningEnabled = enabled;
mLatch.countDown();
}
@@ -1092,6 +1180,7 @@
@Override
public void onSetShuffleMode(int shuffleMode) {
mOnSetShuffleModeCalled = true;
+ mControllerInfo = mSession.getCurrentControllerInfo();
mShuffleMode = shuffleMode;
mLatch.countDown();
}
diff --git a/mediarouter/build.gradle b/mediarouter/build.gradle
index a2463a4..2044242 100644
--- a/mediarouter/build.gradle
+++ b/mediarouter/build.gradle
@@ -34,4 +34,6 @@
mavenGroup = LibraryGroups.MEDIAROUTER
inceptionYear = "2013"
description = "Android MediaRouter Support Library"
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/mediarouter/src/main/res/values-af/strings.xml b/mediarouter/src/main/res/values-af/strings.xml
new file mode 100644
index 0000000..1968699
--- /dev/null
+++ b/mediarouter/src/main/res/values-af/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Stelsel"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Toestelle"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Uitsaai-knoppie"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Uitsaai-knoppie. Ontkoppel"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Uitsaai-knoppie. Koppel tans"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Uitsaai-knoppie. Gekoppel"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Saai uit na"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Soek tans toestelle"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ontkoppel"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Hou op uitsaai"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Maak toe"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Speel"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Onderbreek"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Vou uit"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Vou in"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumkunswerk"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volumeglyer"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Geen media is gekies nie"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Geen inligting is beskikbaar nie"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Saai tans skerm uit"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-am/strings.xml b/mediarouter/src/main/res/values-am/strings.xml
new file mode 100644
index 0000000..5e4eb42
--- /dev/null
+++ b/mediarouter/src/main/res/values-am/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"ሥርዓት"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"መሣሪያዎች"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"የCast አዝራር"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast አዝራር። ግንኙነት ተቋርጧል"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast አዝራር። በመገናኘት ላይ"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"የCast አዝራር። ተገናኝቷል"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast አድርግ ወደ"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"መሣሪያዎችን በማግኘት ላይ"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ግንኙነት አቋርጥ"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Cast ማድረግ አቁም"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"ዝጋ"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"አጫውት"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"ለአፍታ አቁም"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"አቁም"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ዘርጋ"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ሰብስብ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"የአልበም ስነ-ጥበብ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ተንሸራታች የድምፅ መቆጣጠሪያ"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ምንም ማህደረ መረጃ አልተመረጠም"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ምንም መረጃ አይገኝም"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ማያ ገጽን Cast በማድረግ ላይ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ar/strings.xml b/mediarouter/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..12a6df3
--- /dev/null
+++ b/mediarouter/src/main/res/values-ar/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"النظام"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"الأجهزة"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"زر الإرسال"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"زر الإرسال. تم قطع الاتصال"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"زر الإرسال. جارٍ الاتصال"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"زر الإرسال. تم الاتصال"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"إرسال إلى"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"جارٍ البحث عن أجهزة"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"قطع الاتصال"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"إيقاف الإرسال"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"إغلاق"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"تشغيل"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"إيقاف مؤقت"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"إيقاف"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"توسيع"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"تصغير"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"صورة الألبوم"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"شريط تمرير مستوى الصوت"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"لم يتم اختيار أي وسائط"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"لا تتوفر أي معلومات"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"جارٍ إرسال الشاشة"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-az/strings.xml b/mediarouter/src/main/res/values-az/strings.xml
index 8f3b518..651c84c 100644
--- a/mediarouter/src/main/res/values-az/strings.xml
+++ b/mediarouter/src/main/res/values-az/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"Sistem"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Cihazlar"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Yayım düyməsi"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Yayım düyməsi. Bağlantı kəsildi"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Yayım düyməsi. Qoşulur"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Yayım düyməsi. Qoşuldu"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Bura yayımlayın"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Cihazlar axtarılır"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Əlaqəni silin"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Yayımı dayandırın"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Bağlayın"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Oyun"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pauza"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"Dayandırın"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Genişləndirin"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Yığcamlaşdırın"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Albom incəsənəti"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Səs ayarlayıcısı"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"Media seçilməyib"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"Əlçatan məlumat yoxdur"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Ekran yayımlanır"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Cihazlar"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Yayım düyməsi"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Yayım düyməsi. Bağlantı kəsildi"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Yayım düyməsi. Qoşulur"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Yayım düyməsi. Qoşuldu"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Bura yayımlayın"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Cihazlar axtarılır"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ayırın"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Yayımı dayandırın"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Bağlayın"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Fasilə verin"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Dayandırın"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Dayandırın"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Genişləndirin"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Yığcamlaşdırın"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albom incəsənəti"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Səs ayarlayıcısı"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Media seçilməyib"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Əlçatan məlumat yoxdur"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekran yayımlanır"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-b+sr+Latn/strings.xml b/mediarouter/src/main/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..805709b
--- /dev/null
+++ b/mediarouter/src/main/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Uređaji"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Dugme Prebaci"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Dugme Prebaci. Veza je prekinuta"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Dugme Prebaci. Povezuje se"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Dugme Prebaci. Povezan je"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Prebacite na"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Traže se uređaji"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini vezu"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zaustavi prebacivanje"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zatvori"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Pusti"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauziraj"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Zaustavi"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Proširi"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skupi"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Omot albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Klizač za jačinu zvuka"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nema izabranih medija"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nema dostupnih informacija"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Prebacuje se ekran"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-be/strings.xml b/mediarouter/src/main/res/values-be/strings.xml
new file mode 100644
index 0000000..b0ae4d5
--- /dev/null
+++ b/mediarouter/src/main/res/values-be/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Сістэма"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Прылады"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Кнопка трансляцыі"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Кнопка трансляцыі. Прылада адключана"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Кнопка трансляцыі. Прылада падключаецца"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Кнопка трансляцыі. Прылада падключана"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Трансліраваць на прыладу"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Пошук прылад"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Адключыць"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Спыніць трансляцыю"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Закрыць"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Прайграць"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Паўза"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Спыніць"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Разгарнуць"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Згарнуць"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Вокладка альбома"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Рэгулятар гучнасці"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Медыяфайл не выбраны"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Інфармацыя адсутнічае"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Экран трансліруецца"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-bg/strings.xml b/mediarouter/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000..7491533
--- /dev/null
+++ b/mediarouter/src/main/res/values-bg/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Система"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Устройства"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Бутон за предаване"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Бутон за предаване. Връзката е прекратена"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Бутон за предаване. Установява се връзка"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Бутон за предаване. Установена е връзка"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Предаване към"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Търсят се устройства"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Прекратяване на връзката"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Спиране на предаването"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Затваряне"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Възпроизвеждане"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Поставяне на пауза"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Спиране"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Разгъване"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Свиване"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Обложка на албума"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Плъзгач за силата на звука"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Няма избрана мултимедия"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Няма налична информация"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Екранът се предава"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-bn/strings.xml b/mediarouter/src/main/res/values-bn/strings.xml
new file mode 100644
index 0000000..b3ed757
--- /dev/null
+++ b/mediarouter/src/main/res/values-bn/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"সিস্টেম"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ডিভাইস"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"কাস্ট করার বোতাম"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"কাস্ট করার বোতাম। কানেক্ট করা নেই"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"কাস্ট করার বোতাম। কানেক্ট করা হচ্ছে"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"কাস্ট করার বোতাম। কানেক্ট হয়েছে"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"এখানে কাস্ট করুন"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"ডিভাইস খোঁজা হচ্ছে"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ডিসকানেক্ট"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"কাস্ট করা বন্ধ করুন"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"বন্ধ করুন"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"চালান"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"পজ করুন"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"থামান"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"বড় করে দেখুন"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"আড়াল করুন"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"অ্যালবাম আর্ট"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ভলিউম স্লাইডার"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"কোনও মিডিয়া বেছে নেওয়া হয়নি"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"কোনও তথ্য উপলভ্য নেই"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"স্ক্রিন কাস্ট করা হচ্ছে"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-bs/strings.xml b/mediarouter/src/main/res/values-bs/strings.xml
new file mode 100644
index 0000000..553efdf
--- /dev/null
+++ b/mediarouter/src/main/res/values-bs/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Uređaji"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Dugme za emitiranje"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Dugme za emitiranje. Veza je prekinuta"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Dugme za emitiranje. Povezivanje"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Dugme za emitiranje. Povezano"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Emitiranje na"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Traženje uređaja"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini vezu"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zaustavi emitiranje"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zatvori"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproduciraj"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauza"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Zaustavi"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Proširi"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skupi"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Omot albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Klizač za jačinu zvuka"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nije odabran nijedan medij"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nema dostupnih informacija"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Emitiranje ekrana"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ca/strings.xml b/mediarouter/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..e6a2f71
--- /dev/null
+++ b/mediarouter/src/main/res/values-ca/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositius"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botó d\'emetre"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botó d\'emetre. Desconnectat."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botó d\'emetre. S\'està connectant."</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botó d\'emetre. Connectat."</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Emet contingut a"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"S\'estan cercant dispositius"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconnecta"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Atura l\'emissió"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Tanca"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reprodueix"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Posa en pausa"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Atura"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Desplega"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Replega"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Imatge de l\'àlbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control lliscant de volum"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No hi ha contingut multimèdia seleccionat"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No hi ha informació disponible"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"S\'està emetent la pantalla"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-cs/strings.xml b/mediarouter/src/main/res/values-cs/strings.xml
new file mode 100644
index 0000000..a914d34
--- /dev/null
+++ b/mediarouter/src/main/res/values-cs/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Systém"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Zařízení"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Tlačítko odesílání"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Tlačítko odesílání. Odpojeno"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Tlačítko odesílání. Připojování"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Tlačítko odesílání. Připojeno"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Odeslat do zařízení"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Hledání zařízení"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Odpojit"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zastavit odesílání"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zavřít"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Přehrát"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pozastavit"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Ukončit"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Rozbalit"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sbalit"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Obal alba"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Posuvník hlasitosti"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Není vybrán žádný mediální obsah"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nejsou k dispozici žádné informace"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Odesílání obsahu obrazovky"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-da/strings.xml b/mediarouter/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000..5736cb5
--- /dev/null
+++ b/mediarouter/src/main/res/values-da/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Enheder"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-knap"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-knap. Forbindelsen er afbrudt"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-knap. Opretter forbindelse"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-knap. Tilsluttet"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast til"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finder enheder"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Afbryd"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop med at caste"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Luk"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Afspil"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Sæt på pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Udvid"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skjul"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumgrafik"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Lydstyrkeskyder"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ingen medier er markeret"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Der er ingen tilgængelige oplysninger"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Skærmen castes"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-de/strings.xml b/mediarouter/src/main/res/values-de/strings.xml
new file mode 100644
index 0000000..bfab0be
--- /dev/null
+++ b/mediarouter/src/main/res/values-de/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Geräte"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-Symbol"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-Symbol. Nicht verbunden"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-Symbol. Verbindung wird hergestellt"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-Symbol. Verbunden"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Streamen auf"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Keine Geräte gefunden"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Trennen"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Streaming beenden"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Schließen"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Wiedergeben"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausieren"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Beenden"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Maximieren"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Minimieren"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumcover"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Schieberegler für die Lautstärke"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Keine Medien ausgewählt"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Keine Informationen verfügbar"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Bildschirm wird übertragen"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-el/strings.xml b/mediarouter/src/main/res/values-el/strings.xml
new file mode 100644
index 0000000..6290c3d
--- /dev/null
+++ b/mediarouter/src/main/res/values-el/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Σύστημα"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Συσκευές"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Κουμπί μετάδοσης"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Κουμπί μετάδοσης. Αποσυνδέθηκε."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Κουμπί μετάδοση. Σύνδεση."</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Κουμπί μετάδοσης. Συνδέθηκε."</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Μετάδοση σε"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Εύρεση συσκευών"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Αποσύνδεση"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Διακοπή μετάδοσης"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Κλείσιμο"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Αναπαραγωγή"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Παύση"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Διακοπή"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Ανάπτυξη"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Σύμπτυξη"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Εξώφυλλο άλμπουμ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Ρυθμιστικό έντασης ήχου"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Δεν επιλέχθηκαν μέσα"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Μετάδοση οθόνης"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-en-rAU/strings.xml b/mediarouter/src/main/res/values-en-rAU/strings.xml
index df5801c..420d536 100644
--- a/mediarouter/src/main/res/values-en-rAU/strings.xml
+++ b/mediarouter/src/main/res/values-en-rAU/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"System"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Devices"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Cast button"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Cast button. Disconnected"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Cast button. Connecting"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Cast button. Connected"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Cast to"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Finding devices"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Disconnect"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Stop casting"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Close"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Play"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pause"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"Stop"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Expand"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Collapse"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Album art"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Volume slider"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"No media selected"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"No info available"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Casting screen"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-en-rCA/strings.xml b/mediarouter/src/main/res/values-en-rCA/strings.xml
index df5801c..420d536 100644
--- a/mediarouter/src/main/res/values-en-rCA/strings.xml
+++ b/mediarouter/src/main/res/values-en-rCA/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"System"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Devices"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Cast button"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Cast button. Disconnected"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Cast button. Connecting"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Cast button. Connected"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Cast to"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Finding devices"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Disconnect"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Stop casting"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Close"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Play"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pause"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"Stop"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Expand"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Collapse"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Album art"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Volume slider"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"No media selected"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"No info available"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Casting screen"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-en-rGB/strings.xml b/mediarouter/src/main/res/values-en-rGB/strings.xml
index df5801c..420d536 100644
--- a/mediarouter/src/main/res/values-en-rGB/strings.xml
+++ b/mediarouter/src/main/res/values-en-rGB/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"System"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Devices"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Cast button"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Cast button. Disconnected"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Cast button. Connecting"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Cast button. Connected"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Cast to"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Finding devices"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Disconnect"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Stop casting"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Close"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Play"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pause"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"Stop"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Expand"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Collapse"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Album art"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Volume slider"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"No media selected"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"No info available"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Casting screen"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-en-rIN/strings.xml b/mediarouter/src/main/res/values-en-rIN/strings.xml
index df5801c..420d536 100644
--- a/mediarouter/src/main/res/values-en-rIN/strings.xml
+++ b/mediarouter/src/main/res/values-en-rIN/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"System"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Devices"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Cast button"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Cast button. Disconnected"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Cast button. Connecting"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Cast button. Connected"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Cast to"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Finding devices"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Disconnect"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Stop casting"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Close"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Play"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pause"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"Stop"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Expand"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Collapse"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Album art"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Volume slider"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"No media selected"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"No info available"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Casting screen"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-en-rXC/strings.xml b/mediarouter/src/main/res/values-en-rXC/strings.xml
index 993d212..03083ad 100644
--- a/mediarouter/src/main/res/values-en-rXC/strings.xml
+++ b/mediarouter/src/main/res/values-en-rXC/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"System"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Devices"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Cast button"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Cast button. Disconnected"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Cast button. Connecting"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Cast button. Connected"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Cast to"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Finding devices"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Disconnect"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Stop casting"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Close"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Play"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pause"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"Stop"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Expand"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Collapse"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Album art"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Volume slider"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"No media selected"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"No info available"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Casting screen"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Devices"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast button"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast button. Disconnected"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast button. Connecting"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast button. Connected"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast to"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finding devices"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnect"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stop casting"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Close"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Play"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stop"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expand"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Collapse"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volume slider"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No media selected"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No info available"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Casting screen"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-es-rUS/strings.xml b/mediarouter/src/main/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..51a2955
--- /dev/null
+++ b/mediarouter/src/main/res/values-es-rUS/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botón para transmitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botón para transmitir (desconectado)"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botón para transmitir (conectando)"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botón para transmitir (conectado)"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir a"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Buscando dispositivos"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Detener transmisión"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Cerrar"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproducir"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Detener"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Contraer"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Imagen del álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control deslizante del volumen"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No se seleccionó ningún contenido multimedia"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Sin información disponible"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Transmitiendo pantalla"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-es/strings.xml b/mediarouter/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000..e07a751
--- /dev/null
+++ b/mediarouter/src/main/res/values-es/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botón de enviar"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botón de enviar. Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botón de enviar. Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botón de enviar. Conectado"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Enviar a"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Buscando dispositivos"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Detener envío"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Cerrar"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproducir"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Detener"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Mostrar"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Ocultar"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Carátula del álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control deslizante de volumen"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"No se ha seleccionado contenido multimedia"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"No hay información disponible"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Enviando pantalla"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-et/strings.xml b/mediarouter/src/main/res/values-et/strings.xml
new file mode 100644
index 0000000..4ff3f62
--- /dev/null
+++ b/mediarouter/src/main/res/values-et/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Süsteem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Seadmed"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Ülekandenupp"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Ülekandenupp. Ühendus on katkestatud"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Ülekandenupp. Ühendamine"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Ülekandenupp. Ühendatud"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Ülekandmine seadmesse"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Seadmete otsimine"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Katkesta ühendus"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Peata ülekandmine"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Sulgemine"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Esitamine"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Peatamine"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Peatamine"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Laiendamine"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Ahendamine"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumi kujundus"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Helitugevuse liugur"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Meediat pole valitud"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Teave pole saadaval"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekraanikuva ülekandmine"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-eu/strings.xml b/mediarouter/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..18aeed3
--- /dev/null
+++ b/mediarouter/src/main/res/values-eu/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Gailuak"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Igorri botoia"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Igortzeko botoia. Deskonektatuta"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Igortzeko botoia. Konektatzen"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Igortzeko botoia. Konektatuta"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Igorri hona"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Gailuak bilatzen"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Deskonektatu"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Utzi igortzeari"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Itxi"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Erreproduzitu"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausatu"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Gelditu"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Zabaldu"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Tolestu"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumaren azala"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Bolumenaren graduatzailea"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ez da ezer hautatu"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ez dago informaziorik"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Pantaila igortzen"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-fa/strings.xml b/mediarouter/src/main/res/values-fa/strings.xml
new file mode 100644
index 0000000..eb0ea6c
--- /dev/null
+++ b/mediarouter/src/main/res/values-fa/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"سیستم"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"دستگاهها"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"دکمه ارسال محتوا"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"دکمه فرستادن. اتصال قطع شد"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"دکمه فرستادن. درحال اتصال"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"دکمه فرستادن. متصل"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ارسال محتوا به"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"پیدا کردن دستگاهها"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"قطع اتصال"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"توقف ارسال محتوا"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"بستن"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"پخش"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"مکث"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"توقف"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"بزرگ کردن"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"کوچک کردن"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"عکس روی جلد آلبوم"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"لغزنده میزان صدا"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"رسانهای انتخاب نشده است"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"اطلاعات دردسترس نیست"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"صفحه ارسال محتوا"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-fi/strings.xml b/mediarouter/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..a365147
--- /dev/null
+++ b/mediarouter/src/main/res/values-fi/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Järjestelmä"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Laitteet"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-painike"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-painike. Yhteys katkaistu"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-painike. Yhdistetään"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-painike. Yhdistetty"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Suoratoiston kohde"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Etsitään laitteita"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Katkaise yhteys"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Lopeta suoratoisto"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Sulje"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Toista"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Keskeytä"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Lopeta"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Laajenna"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Tiivistä"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumin kansikuva"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Äänenvoimakkuuden liukusäädin"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ei valittua mediaa"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ei tietoja saatavilla"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Suoratoistetaan näyttöä"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-fr-rCA/strings.xml b/mediarouter/src/main/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..8df9031
--- /dev/null
+++ b/mediarouter/src/main/res/values-fr-rCA/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Système"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Appareils"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Bouton Diffuser"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Bouton Diffuser. Déconnecté"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Bouton Diffuser. Connexion en cours…"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Bouton Diffuser. Connecté"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Diffuser vers"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Recherche d\'appareils"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Dissocier"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Arrêter la diffusion"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Fermer"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Lire"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Arrêter"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Développer"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Réduire"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Image de l\'album"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Curseur de réglage du volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Aucun média sélectionné"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Aucune donnée trouvée"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Diffusion de l\'écran en cours"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-fr/strings.xml b/mediarouter/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..cfce49b
--- /dev/null
+++ b/mediarouter/src/main/res/values-fr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Système"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Appareils"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Icône Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Icône Cast. Déconnecté"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Icône Cast. Connexion…"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Icône Cast. Connecté"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Caster sur"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Recherche d\'appareils…"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Déconnecter"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Arrêter la diffusion"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Fermer"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Lecture"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Arrêt"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Développer"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Réduire"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Image de l\'album"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Curseur de volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Aucun contenu multimédia sélectionné"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Aucune information disponible"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Diffusion de l\'écran"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-gl/strings.xml b/mediarouter/src/main/res/values-gl/strings.xml
new file mode 100644
index 0000000..2eb5e04
--- /dev/null
+++ b/mediarouter/src/main/res/values-gl/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botón de emitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botón de emitir. Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botón de emitir. Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botón de emitir. Conectado"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Emitir en"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Buscando dispositivos"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Deter emisión"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Pechar"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproducir"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Deter"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Despregar"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Contraer"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Portada do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Control desprazable do volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Non se seleccionou ningún recurso multimedia"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Non hai información dispoñible"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Emitindo a pantalla"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-gu/strings.xml b/mediarouter/src/main/res/values-gu/strings.xml
new file mode 100644
index 0000000..8459bcd
--- /dev/null
+++ b/mediarouter/src/main/res/values-gu/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"સિસ્ટમ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ઉપકરણો"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"કાસ્ટ બટન"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"કાસ્ટ બટન. ડિસ્કનેક્ટેડ"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"કાસ્ટ બટન. કનેક્ટ કરી રહ્યાં છીએ"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"કાસ્ટ બટન. કનેક્ટેડ"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"આના પર કાસ્ટ કરો"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"ઉપકરણો શોધી રહ્યાં છીએ"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ડિસ્કનેક્ટ કરો"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"કાસ્ટ કરવાનું રોકો"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"બંધ કરો"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ચલાવો"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"થોભાવો"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"રોકો"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"વિસ્તાર કરો"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"સંકુચિત કરો"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"આલ્બમ આર્ટ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"વૉલ્યુમ સ્લાઇડર"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"કોઈ મીડિયા પસંદ કરેલ નથી"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"સ્ક્રીનને કાસ્ટ કરી રહ્યાં છીએ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-hi/strings.xml b/mediarouter/src/main/res/values-hi/strings.xml
new file mode 100644
index 0000000..891d765
--- /dev/null
+++ b/mediarouter/src/main/res/values-hi/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"सिस्टम"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"डिवाइस"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"कास्ट करें बटन"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"कास्ट करें बटन. नहीं जुड़ा है"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"कास्ट करें बटन. जुड़ रहा है"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"कास्ट करें बटन. जुड़ा है"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"इस पर कास्ट करें"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"डिवाइस ढूंढे जा रहे हैं"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"कनेक्शन हटाएं"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"कास्ट करना रोकें"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"बंद करें"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"चलाएं"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"रोकें"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"रुकें"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"सदस्याें की सूची को बड़ा करके देखें"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"सदस्याें की सूची छोटी करें"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"एल्बम आर्ट"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"आवाज़ बढ़ाने या घटाने वाला स्लाइडर"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"कोई मीडिया चुना नहीं गया"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"कोई जानकारी मौजूद नहीं है"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"स्क्रीन कास्ट की जा रही है"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-hr/strings.xml b/mediarouter/src/main/res/values-hr/strings.xml
new file mode 100644
index 0000000..e17a0e7
--- /dev/null
+++ b/mediarouter/src/main/res/values-hr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sustav"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Uređaji"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Gumb za emitiranje"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Gumb za emitiranje. Veza prekinuta"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Gumb za emitiranje. Povezivanje"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Gumb za emitiranje. Povezan"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Emitiranje na"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Traženje uređaja"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zaustavi emitiranje"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zatvori"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Pokreni"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauza"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Zaustavi"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Proširi"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sažmi"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Naslovnica albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Klizač za glasnoću"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nije odabran nijedan medij"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Informacije nisu dostupne"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Emitiranje zaslona"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-hu/strings.xml b/mediarouter/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000..a9f80f4
--- /dev/null
+++ b/mediarouter/src/main/res/values-hu/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Rendszer"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Eszközök"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Átküldés gomb"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Átküldés gomb. Kapcsolat bontva"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Átküldés gomb. Csatlakozás"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Átküldés gomb. Csatlakoztatva"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Átküldés ide:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Eszközök keresése"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Leválasztás"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Átküldés leállítása"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Bezárás"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Lejátszás"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Szünet"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Leállítás"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Kibontás"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Összecsukás"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Lemezborító"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Hangerőszabályzó"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nincs médiatartalom kiválasztva"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nincs információ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Képernyőtartalom átküldése…"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-hy/strings.xml b/mediarouter/src/main/res/values-hy/strings.xml
new file mode 100644
index 0000000..e48fac5
--- /dev/null
+++ b/mediarouter/src/main/res/values-hy/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Համակարգ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Սարքեր"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Հեռարձակման կոճակ"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Հեռարձակման կոճակ: Սարքն անջատած է:"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Հեռարձակման կոճակ: Սարքը միանում է:"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Հեռարձակման կոճակ: Սարքը միացված է:"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Ընտրեք սարք"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Սարքերի որոնում"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Անջատել"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Դադարեցնել հեռարձակումը"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Փակել"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Նվագարկել"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Ընդհատել"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Դադարեցնել"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Ընդարձակել"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Կոծկել"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Ալբոմի շապիկ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Ձայնի ուժգնության կարգավորիչ"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Մեդիա ֆայլ չի ընտրվել"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Հասանելի տեղեկություններ չկան"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Էկրանի հեռարձակում"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-in/strings.xml b/mediarouter/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000..5a19254
--- /dev/null
+++ b/mediarouter/src/main/res/values-in/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Perangkat"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Tombol Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Tombol Cast. Terputus"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Tombol Cast. Menghubungkan"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Tombol Cast. Terhubung"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast ke"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Mencari perangkat"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Putuskan hubungan"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Hentikan cast"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Tutup"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Putar"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Jeda"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Berhenti"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Luaskan"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Ciutkan"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Sampul album"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Penggeser volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Tidak ada media yang dipilih"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Tidak ada info yang tersedia"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Melakukan cast layar"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-is/strings.xml b/mediarouter/src/main/res/values-is/strings.xml
new file mode 100644
index 0000000..bc3c36d
--- /dev/null
+++ b/mediarouter/src/main/res/values-is/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Kerfi"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Tæki"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Útsendingarhnappur"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Útsendingarhnappur. Aftengt"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Útsendingarhnappur. Tengist"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Útsendingarhnappur. Tengt"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Senda út í"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Leitað að tækj"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Aftengja"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stöðva útsendingu"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Loka"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Spila"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Hlé"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stöðva"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Stækka"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Minnka"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Plötuumslag"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Hljóðstyrkssleði"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ekkert efni valið"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Engar upplýsingar í boði"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Skjár sendur út"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-it/strings.xml b/mediarouter/src/main/res/values-it/strings.xml
new file mode 100644
index 0000000..3bbfecd
--- /dev/null
+++ b/mediarouter/src/main/res/values-it/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivi"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Pulsante Trasmetti"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Pulsante Trasmetti. Disconnesso"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Pulsante Trasmetti. Connessione in corso"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Pulsante Trasmetti. Connesso"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Trasmetti a"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Ricerca di dispositivi"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Disconnetti"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Interrompi trasmissione"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Chiudi"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Riproduci"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Metti in pausa"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Interrompi"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Espandi"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Comprimi"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Copertina"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Dispositivo di scorrimento del volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nessun contenuto multimediale selezionato"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nessuna informazione disponibile"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Trasmissione dello schermo"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-iw/strings.xml b/mediarouter/src/main/res/values-iw/strings.xml
new file mode 100644
index 0000000..72ebc9c
--- /dev/null
+++ b/mediarouter/src/main/res/values-iw/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"מערכת"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"מכשירים"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"לחצן הפעלת Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"לחצן הפעלת Cast. מנותק"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"לחצן הפעלת Cast. מתחבר"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"לחצן הפעלת Cast. מחובר"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"העברה אל"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"מחפש מכשירים"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ניתוק"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"עצירת העברה"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"סגירה"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"הפעלה"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"השהיה"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"הפסקה"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"הרחבה"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"כיווץ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"עטיפת אלבום"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"מחוון עוצמה"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"לא נבחרה מדיה"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"אין מידע זמין"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"העברת מסך מתבצעת"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ja/strings.xml b/mediarouter/src/main/res/values-ja/strings.xml
new file mode 100644
index 0000000..b33ffb9
--- /dev/null
+++ b/mediarouter/src/main/res/values-ja/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"システム"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"端末"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"キャスト アイコン"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"キャスト アイコン。接続解除済み"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"キャスト アイコン。接続中"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"キャスト アイコン。接続済み"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"キャスト先"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"端末を検索しています"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"接続を解除"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"キャストを停止"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"閉じる"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"再生"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"一時停止"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"停止"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"展開"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"折りたたむ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"アルバムアート"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量スライダー"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"メディアを選択していません"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"情報がありません"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"画面をキャストしています"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ka/strings.xml b/mediarouter/src/main/res/values-ka/strings.xml
new file mode 100644
index 0000000..446a9e0
--- /dev/null
+++ b/mediarouter/src/main/res/values-ka/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"სისტემა"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"მოწყობილობები"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"ტრანსლირების ღილაკი"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ტრანსლირების ღილაკი. გათიშული"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ტრანსლირების ღილაკი. მიმდინარეობს დაკავშირება"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"ტრანსლირების ღილაკი. დაკავშირებული"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ტრანსლირება:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"მოწყობილობების მოძიება..."</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"გათიშვა"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ტრანსლირების შეწყვეტა"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"დახურვა"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"დაკვრა"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"პაუზა"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"შეწყვეტა"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"გაშლა"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ჩაკეცვა"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ალბომის გარეკანი"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ხმის სლაიდერი"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"მედია არჩეული არ არის"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"მიმდინარეობს ეკრანის ტრანსლირება"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-kk/strings.xml b/mediarouter/src/main/res/values-kk/strings.xml
new file mode 100644
index 0000000..d512ff9
--- /dev/null
+++ b/mediarouter/src/main/res/values-kk/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Жүйе"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Құрылғылар"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Трансляциялау түймесі"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Трансляциялау түймесі. Ажыратылды"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Трансляциялау түймесі. Қосылуда"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Трансляциялау түймесі. Қосылды"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Трансляция:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Құрылғылар ізделуде"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ажырату"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Трансляцияны тоқтату"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Жабу"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Ойнату"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Кідірту"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Тоқтату"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Жаю"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Жию"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Альбомның мұқабасы"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Дыбыс деңгейінің жүгірткісі"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ешқандай медиафайл таңдалмаған"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Қолжетімді ақпарат жоқ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Экранды трансляциялау"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-km/strings.xml b/mediarouter/src/main/res/values-km/strings.xml
new file mode 100644
index 0000000..9303a1b
--- /dev/null
+++ b/mediarouter/src/main/res/values-km/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"ប្រព័ន្ធ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ឧបករណ៍"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"ប៊ូតុងបញ្ជូន"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ប៊ូតុងបញ្ជូន។ បានផ្តាច់"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ប៊ូតុងបញ្ជូន។ កំពុងភ្ជាប់"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"ប៊ូតុងបញ្ជូន។ បានភ្ជាប់ហើយ"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"បញ្ជូនទៅ"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"កំពុងស្វែងរកឧបករណ៍"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ផ្ដាច់"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"បញ្ឈប់ការបញ្ជូន"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"បិទ"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ចាក់"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"ផ្អាក"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"បញ្ឈប់"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ពង្រីក"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"បង្រួម"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"រូបភាពសិល្បៈក្របអាល់ប៊ុម"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"របារកម្រិតសំឡេង"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"មិនបានជ្រើសរើសមេឌៀទេ"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"មិនមានព័ត៌មានទេ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"កំពុងបញ្ជូនអេក្រង់"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-kn/strings.xml b/mediarouter/src/main/res/values-kn/strings.xml
new file mode 100644
index 0000000..f495017
--- /dev/null
+++ b/mediarouter/src/main/res/values-kn/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"ಸಿಸ್ಟಂ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ಸಾಧನಗಳು"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"ಬಿತ್ತರಿಸು ಬಟನ್"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ಬಿತ್ತರಿಸು ಬಟನ್. ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ಬಿತ್ತರಿಸು ಬಟನ್. ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"ಬಿತ್ತರಿಸು ಬಟನ್. ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ಇದಕ್ಕೆ ಬಿತ್ತರಿಸಿ"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿ"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ಬಿತ್ತರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿ"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"ಮುಚ್ಚಿ"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ಪ್ಲೇ"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"ವಿರಾಮ"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"ನಿಲ್ಲಿಸಿ"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ಹಿಗ್ಗಿಸಿ"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ಕುಗ್ಗಿಸಿ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ಆಲ್ಬಮ್ ಕಲೆ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ಯಾವುದೇ ಮಾಧ್ಯಮ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ಪರದೆಯನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ko/strings.xml b/mediarouter/src/main/res/values-ko/strings.xml
new file mode 100644
index 0000000..178fab0
--- /dev/null
+++ b/mediarouter/src/main/res/values-ko/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"시스템"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"기기"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"전송 버튼"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"전송 버튼. 연결 해제됨"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"전송 버튼. 연결 중"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"전송 버튼. 연결됨"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"전송 대상"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"기기를 찾는 중"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"연결 끊기"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"전송 중지"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"닫기"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"재생"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"일시중지"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"중지"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"확대"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"접기"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"앨범아트"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"볼륨 슬라이더"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"선택된 미디어 없음"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"사용할 수 있는 정보 없음"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"화면 전송 중"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ky/strings.xml b/mediarouter/src/main/res/values-ky/strings.xml
new file mode 100644
index 0000000..100e5a5
--- /dev/null
+++ b/mediarouter/src/main/res/values-ky/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Тутум"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Түзмөктөр"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Тышкы экранга чыгаруу баскычы"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Тышкы экранга чыгаруу баскычы. Түзмөк ажырап турат."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Тышкы экранга чыгаруу баскычы. Түзмөк туташууда"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Тышкы экранга чыгаруу баскычы. Түзмөк туташып турат"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Түзмөккө чыгаруу"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Түзмөктөр изделүүдө"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ажыратуу"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Тышкы экранга чыгарууну токтотуу"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Жабуу"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Угуу"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Тыным"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Токтотуу"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Жайып көрсөтүү"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Жыйыштыруу"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Альбом мукабасы"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Үндү катуулатуучу сыдырма"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Эч нерсе тандалган жок"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Эч маалымат жок"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Тышкы экранга чыгарылууда"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-lo/strings.xml b/mediarouter/src/main/res/values-lo/strings.xml
new file mode 100644
index 0000000..79bd210
--- /dev/null
+++ b/mediarouter/src/main/res/values-lo/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"ລະບົບ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ອຸປະກອນ"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"ປຸ່ມສົ່ງສັນຍານ"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ປຸ່ມສົ່ງສັນຍານ. ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ປຸ່ມສົ່ງສັນຍານ. ກຳລັງເຊື່ອມຕໍ່"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"ປຸ່ມສົ່ງສັນຍານ. ເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ສົ່ງສັນຍານໄປທີ່"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"ກຳລັງຊອກຫາອຸປະກອນ"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ຕັດການເຊື່ອມຕໍ່"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ຢຸດການສົ່ງສັນຍານ"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"ປິດ"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ຫຼິ້ນ"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"ຢຸດຊົ່ວຄາວ"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"ຢຸດ"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ຂະຫຍາຍ"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ຫຍໍ້ລົງ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ໜ້າປົກອະລະບໍ້າ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ຕົວປັບລະດັບສຽງ"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ບໍ່ໄດ້ເລືອກສື່ໃດ"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ບໍ່ມີຂໍ້ມູນ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ກຳລັງສົ່ງສັນຍານພາບ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-lt/strings.xml b/mediarouter/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000..6f1ce9f
--- /dev/null
+++ b/mediarouter/src/main/res/values-lt/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Įrenginiai"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Perdavimo mygtukas"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Perdavimo mygtukas. Atsijungta"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Perdavimo mygtukas. Prisijungiama"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Perdavimo mygtukas. Prisijungta"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Perduoti į"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Randami įrenginiai"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Atsijungti"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Sustabdyti perdavimą"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Uždaryti"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Leisti"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pristabdyti"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Sustabdyti"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Išskleisti"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sutraukti"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumo viršelis"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Garsumo šliaužiklis"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nepasirinkta jokios medijos"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Informacija nepasiekiama"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Perduodamas ekranas"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-lv/strings.xml b/mediarouter/src/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..56432f8
--- /dev/null
+++ b/mediarouter/src/main/res/values-lv/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistēma"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Ierīces"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Apraides poga"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Apraides poga. Savienojums pārtraukts."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Apraides poga. Notiek savienojuma izveide."</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Apraides poga. Savienojums izveidots."</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Apraides veikšana uz ierīci"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Ierīču meklēšana"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Atvienot"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Apturēt apraidi"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Aizvērt"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Atskaņot"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauzēt"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Apturēt"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Izvērst"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Sakļaut"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albuma vāciņš"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Skaļuma slīdnis"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nav atlasīts multivides saturs"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nav informācijas"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Notiek ekrāna apraide"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-mk/strings.xml b/mediarouter/src/main/res/values-mk/strings.xml
new file mode 100644
index 0000000..e4572c5
--- /dev/null
+++ b/mediarouter/src/main/res/values-mk/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Систем"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Уреди"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Копче за Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Копче за Cast. Исклучено"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Копче за Cast. Се поврзува"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Копче за Cast. Поврзано"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Емитување на"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Се бараат уреди"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Исклучи"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Сопри со емитување"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Затвори"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Пушти"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Паузирај"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Сопри"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Прошири"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Собери"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Корица на албум"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Лизгач за јачина на звук"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Не се избрани аудиовизуелни датотеки"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Нема достапни информации"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Се емитува екран"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ml/strings.xml b/mediarouter/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..d7c987b
--- /dev/null
+++ b/mediarouter/src/main/res/values-ml/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"സിസ്റ്റം"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ഉപകരണങ്ങൾ"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"കാസ്റ്റ് ബട്ടൺ"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റ് ചെയ്യുന്നു"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റ് ചെയ്തു"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ഇതിലേക്ക് കാസ്റ്റ് ചെയ്യുക"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"വിച്ഛേദിക്കുക"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"അവസാനിപ്പിക്കുക"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"പ്ലേ ചെയ്യുക"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"താൽക്കാലികമായി നിർത്തുക"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"നിര്ത്തുക"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"വികസിപ്പിക്കുക"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ചുരുക്കുക"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ആൽബം ആർട്ട്"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ശബ്ദ സ്ലൈഡർ"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"സ്ക്രീൻ കാസ്റ്റ് ചെയ്യുന്നു"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-mn/strings.xml b/mediarouter/src/main/res/values-mn/strings.xml
new file mode 100644
index 0000000..9f03518
--- /dev/null
+++ b/mediarouter/src/main/res/values-mn/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Систем"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Төхөөрөмж"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Дамжуулах товч"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Дамжуулах товч. Салсан"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Дамжуулах товч. Холбогдож байна"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Дамжуулах товч. Холбогдсон"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Дамжуулах"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Төхөөрөмжийг хайж байна"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Салгах"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Дамжуулахыг зогсоох"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Хаах"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Тоглуулах"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Түр зогсоох"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Зогсоох"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Дэлгэх"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Хумих"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Цомгийн зураг"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Дууны түвшин тааруулагч"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ямар ч медиа сонгоогүй байна"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Мэдээлэл байхгүй байна"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Дэлгэцийг дамжуулж байна"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-mr/strings.xml b/mediarouter/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..f3ccbb9
--- /dev/null
+++ b/mediarouter/src/main/res/values-mr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"सिस्टम"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"डिव्हाइस"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"कास्ट बटण"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"कास्ट बटण. डिस्कनेक्ट केले"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"कास्ट बटण. कनेक्ट करत आहे"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"कास्ट बटण. कनेक्ट केले"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"यावर कास्ट करा"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"डिव्हाइस शोधत आहे"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"डिस्कनेक्ट करा"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"कास्ट करणे थांबवा"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"बंद"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"खेळा"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"विराम द्या"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"थांबा"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"विस्तार करा"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"कोलॅप्स"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"अल्बम कला"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"व्हॉल्यूम स्लायडर"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"मीडिया निवडला नाही"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"कोणतीही माहिती उपलब्ध नाही"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"स्क्रीन कास्ट करत आहे"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ms/strings.xml b/mediarouter/src/main/res/values-ms/strings.xml
new file mode 100644
index 0000000..5096704
--- /dev/null
+++ b/mediarouter/src/main/res/values-ms/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Peranti"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Butang hantar"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Butang hantar. Sambungan diputuskan"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Butang hantar. Menyambung"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Butang hantar. Disambungkan"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Hantar ke"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Mencari peranti"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Putuskan sambungan"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Berhenti menghantar"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Tutup"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Main"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Jeda"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Berhenti"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Kembangkan"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Runtuhkan"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Seni album"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Peluncur kelantangan"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Tiada media yang dipilih"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Maklumat tidak tersedia"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Menghantar skrin"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-my/strings.xml b/mediarouter/src/main/res/values-my/strings.xml
new file mode 100644
index 0000000..5e843a0
--- /dev/null
+++ b/mediarouter/src/main/res/values-my/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"စနစ်"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"စက်များ"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"ကာစ်ခလုတ်"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ကာစ်ခလုတ်။ ချိတ်ဆက်မထားပါ"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ကာစ်ခလုတ်။ ချိတ်ဆက်နေသည်"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"ကာစ်ခလုတ်။ ချိတ်ဆက်ထားသည်"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ဤစက်သို့ ကာစ်လုပ်ရန်"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"စက်များ ရှာနေသည်"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ချိတ်ဆက်မှု ဖြုတ်ရန်"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ကာစ်လုပ်ခြင်းကို ရပ်ရန်"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"ပိတ်ရန်"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ဖွင့်ရန်"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"ခဏရပ်ရန်"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"ရပ်ရန်"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ချဲ့ရန်"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"လျှော့ပြရန်"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"အယ်လ်ဘမ်ပုံ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"အသံအတိုးအကျယ်ချိန်သည့် ဆလိုက်ဒါ"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"မီဒီယာ ရွေးမထားပါ"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"အချက်အလက် မရရှိနိုင်ပါ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ကာစ်တ်လုပ်သည့် မျက်နှာပြင်"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-nb/strings.xml b/mediarouter/src/main/res/values-nb/strings.xml
new file mode 100644
index 0000000..487b9d5
--- /dev/null
+++ b/mediarouter/src/main/res/values-nb/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Enheter"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-ikonet"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-ikonet. Frakoblet"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-ikonet. Kobler til"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-ikonet. Tilkoblet"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Cast til"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Finner enheter"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Koble fra"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Stopp castingen"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Lukk"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Spill av"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Sett på pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stopp"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Vis"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Skjul"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumgrafikk"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Glidebryter for volum"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ingen medier er valgt"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ingen informasjon er tilgjengelig"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Caster skjermen"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ne/strings.xml b/mediarouter/src/main/res/values-ne/strings.xml
new file mode 100644
index 0000000..8a13ac7
--- /dev/null
+++ b/mediarouter/src/main/res/values-ne/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"प्रणाली"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"यन्त्रहरू"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast बटन"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast बटन। जडान विच्छेद गरियो"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast बटन। जडान गरिँदै छ"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast बटन। जडान गरियो"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"यसमा Cast गर्नुहोस्"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"यन्त्रहरू पत्ता लगाइँदै छ"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"विच्छेद गर्नुहोस्"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Cast गर्न छाड्नुहोस्"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"बन्द गर्नुहोस्"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"प्ले गर्नुहोस्"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"पज गर्नुहोस्"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"रोक्नुहोस्"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"विस्तृत गर्नुहोस्"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"संक्षिप्त गर्नुहोस्"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"एल्बम आर्ट"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"भोल्युमको स्लाइडर"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"कुनै पनि मिडिया चयन गरिएन"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"कुनै पनि जानकारी उपलब्ध छैन"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"स्क्रिन Cast गरिँदै छ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-nl/strings.xml b/mediarouter/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000..eb19187
--- /dev/null
+++ b/mediarouter/src/main/res/values-nl/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Systeem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Apparaten"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-knop"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-icoon. Verbinding verbroken"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-icoon. Verbinding maken"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-icoon. Verbonden"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Casten naar"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Apparaten zoeken"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Loskoppelen"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Casten stoppen"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Sluiten"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Afspelen"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauzeren"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stoppen"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Uitvouwen"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Samenvouwen"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albumhoes"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volumeschuifregelaar"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Geen media geselecteerd"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Geen informatie beschikbaar"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Scherm casten"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-pa/strings.xml b/mediarouter/src/main/res/values-pa/strings.xml
new file mode 100644
index 0000000..5092ae0
--- /dev/null
+++ b/mediarouter/src/main/res/values-pa/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"ਸਿਸਟਮ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"ਡੀਵਾਈਸ"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ। ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"\'ਕਾਸਟ ਕਰੋ\' ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"ਏਥੇ ਕਾਸਟ ਕਰੋ"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"ਡੀਵਾਈਸ ਲੱਭੇ ਜਾ ਰਹੇ ਹਨ"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"ਬੰਦ ਕਰੋ"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ਚਲਾਓ"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"ਰੋਕੋ"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"ਬੰਦ ਕਰੋ"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ਸਮੇਟੋ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ਐਲਬਮ ਕਲਾ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ਵੌਲਯੂਮ ਸਲਾਈਡਰ"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ਕੋਈ ਮੀਡੀਆ ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"ਸਕ੍ਰੀਨ \'ਤੇ ਕਾਸਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-pl/strings.xml b/mediarouter/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..6f52faf
--- /dev/null
+++ b/mediarouter/src/main/res/values-pl/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Urządzenia"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Przycisk Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Przycisk Cast. Rozłączono"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Przycisk Cast. Łączę"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Przycisk Cast. Połączono"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Przesyłaj na"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Znajdowanie urządzeń"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Odłącz"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zatrzymaj przesyłanie"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zamknij"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Odtwórz"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Wstrzymaj"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Zatrzymaj"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Rozwiń"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Zwiń"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Okładka albumu"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Suwak głośności"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nie wybrano multimediów"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Brak informacji"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Przesyłanie ekranu"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-pt-rBR/strings.xml b/mediarouter/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..213424a
--- /dev/null
+++ b/mediarouter/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botão \"Transmitir\""</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botão \"Transmitir\". Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botão \"Transmitir\". Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botão \"Transmitir\". Conectado"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir para"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Localizando dispositivos"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Parar transmissão"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Fechar"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproduzir"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Parar"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Recolher"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Arte do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Controle deslizante de volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nenhuma mídia selecionada"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nenhuma informação disponível"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Transmitindo tela"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-pt-rPT/strings.xml b/mediarouter/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..4780144
--- /dev/null
+++ b/mediarouter/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botão Transmitir"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botão Transmitir. Desligado."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botão Transmitir. A ligar..."</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botão Transmitir. Ligado"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir para"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"A localizar dispositivos..."</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desligar"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Parar transmissão"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Fechar"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproduzir"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Interromper"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Parar"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Reduzir"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Imagem do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Controlo de deslize do volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nenhum conteúdo multimédia selecionado."</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nenhuma informação disponível."</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"A transmitir o ecrã..."</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-pt/strings.xml b/mediarouter/src/main/res/values-pt/strings.xml
new file mode 100644
index 0000000..213424a
--- /dev/null
+++ b/mediarouter/src/main/res/values-pt/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistema"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispositivos"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Botão \"Transmitir\""</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Botão \"Transmitir\". Desconectado"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Botão \"Transmitir\". Conectando"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Botão \"Transmitir\". Conectado"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Transmitir para"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Localizando dispositivos"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Desconectar"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Parar transmissão"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Fechar"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Reproduzir"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausar"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Parar"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Expandir"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Recolher"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Arte do álbum"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Controle deslizante de volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nenhuma mídia selecionada"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nenhuma informação disponível"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Transmitindo tela"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ro/strings.xml b/mediarouter/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000..82660fc
--- /dev/null
+++ b/mediarouter/src/main/res/values-ro/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Dispozitive"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Butonul de proiecție"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Butonul de proiecție. Deconectat"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Butonul de proiecție. Se conectează"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Butonul de proiecție. Conectat"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Proiectați pe"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Se caută dispozitive"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Deconectați"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Nu mai proiectați"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Închideți"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Redați"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Întrerupeți"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Opriți"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Extindeți"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Restrângeți"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Grafica albumului"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Glisor pentru volum"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Niciun conținut media selectat"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nu sunt disponibile informații"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Se proiectează ecranul"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ru/strings.xml b/mediarouter/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..b3e5e16
--- /dev/null
+++ b/mediarouter/src/main/res/values-ru/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Система"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Устройства"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Кнопка Google Cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Кнопка трансляции. Устройство отключено."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Кнопка трансляции. Устройство подключается."</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Кнопка трансляции. Устройство подключено."</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Транслировать на устройство"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Поиск устройств…"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Отключить"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Прекратить трансляцию"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Закрыть"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Воспроизвести"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Пауза"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Остановить"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Развернуть"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Скрыть"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Обложка"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Регулятор громкости"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Контент не выбран"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Данных нет"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Подключение к удаленному монитору"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-si/strings.xml b/mediarouter/src/main/res/values-si/strings.xml
new file mode 100644
index 0000000..044f1a3
--- /dev/null
+++ b/mediarouter/src/main/res/values-si/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"පද්ධතිය"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"උපාංග"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"විකාශ බොත්තම"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"විකාශ බොත්තම. විසන්ධි කරන ලදී"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"විකාශ බොත්තම සම්බන්ධ කරමින්"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"විකාශ බොත්තම සම්බන්ධ කරන ලදී"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"විකාශය"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"උපාංග සෙවීම"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"විසන්ධි කරන්න"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"විකාශය නවතන්න"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"වසන්න"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ධාවනය කරන්න"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"විරාම කරන්න"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"නවත්වන්න"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"දිග හරින්න"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"හකුළන්න"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ඇල්බම කලාව"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"හඬ පරිමා ස්ලයිඩරය"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"මාධ්ය තෝරා නැත"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"විකාශ තිරය"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-sk/strings.xml b/mediarouter/src/main/res/values-sk/strings.xml
new file mode 100644
index 0000000..bb81d01
--- /dev/null
+++ b/mediarouter/src/main/res/values-sk/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Systém"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Zariadenia"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Tlačidlo prenosu"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Tlačidlo prenosu. Odpojené"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Tlačidlo prenosu. Pripája sa"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Tlačidlo prenosu. Pripojené"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Prenos do zariadenia"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Hľadajú sa zariadenia"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Odpojiť"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Zastaviť prenos"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zavrieť"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Prehrať"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pozastaviť"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Ukončiť"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Rozbaliť"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Zbaliť"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Obrázok albumu"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Posúvač hlasitosti"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nie sú vybrané žiadne médiá"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nie sú k dispozícii žiadne informácie"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Prenáša sa obrazovka"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-sl/strings.xml b/mediarouter/src/main/res/values-sl/strings.xml
new file mode 100644
index 0000000..2b0eeb8
--- /dev/null
+++ b/mediarouter/src/main/res/values-sl/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Naprave"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Gumb za predvajanje"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Gumb za predvajanje. Povezava je prekinjena."</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Gumb za predvajanje. Vzpostavljanje povezave."</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Gumb za predvajanje. Povezava je vzpostavljena."</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Predvajanje prek:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Iskanje naprav"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Prekini povezavo"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Ustavi predvajanje"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Zapri"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Predvajaj"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Začasno ustavi"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Ustavi"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Razširi"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Strni"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Naslovnica albuma"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Drsnik za glasnost"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Predstavnost ni izbrana"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ni podatkov"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Predvajanje vsebine zaslona"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-sq/strings.xml b/mediarouter/src/main/res/values-sq/strings.xml
new file mode 100644
index 0000000..f172212
--- /dev/null
+++ b/mediarouter/src/main/res/values-sq/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistemi"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Pajisjet"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Butoni i transmetimit"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Butoni i transmetimit. Je i shkëputur"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Butoni i transmetimit. Po lidhet"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Butoni i transmetimit. Je i lidhur"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Transmeto te"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Po kërkon pajisje"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Shkëput"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Ndalo transmetimin"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Mbyll"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Luaj"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauzë"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Ndalo"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Zgjero"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Palos"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Kopertina e albumit"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Rrëshqitësi i volumit"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Nuk është zgjedhur asnjë media"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Nuk jepet asnjë informacion"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Po transmeton ekranin"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-sr/strings.xml b/mediarouter/src/main/res/values-sr/strings.xml
new file mode 100644
index 0000000..e5d3577
--- /dev/null
+++ b/mediarouter/src/main/res/values-sr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Систем"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Уређаји"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Дугме Пребаци"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Дугме Пребаци. Веза је прекинута"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Дугме Пребаци. Повезује се"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Дугме Пребаци. Повезан је"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Пребаците на"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Траже се уређаји"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Прекини везу"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Заустави пребацивање"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Затвори"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Пусти"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Паузирај"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Заустави"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Прошири"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Скупи"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Омот албума"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Клизач за јачину звука"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Нема изабраних медија"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Нема доступних информација"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Пребацује се екран"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-sv/strings.xml b/mediarouter/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000..3ed8212
--- /dev/null
+++ b/mediarouter/src/main/res/values-sv/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Enheter"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast-knappen"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast-knappen. Frånkopplad"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast-knappen. Ansluter"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast-knappen. Ansluten"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Casta till"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Letar efter enheter"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Koppla från"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Sluta casta"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Stäng"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Spela upp"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pausa"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Stoppa"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Utöka"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Komprimera"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Skivomslag"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Volymreglage"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ingen media har valts"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Det finns ingen information"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Skärmen castas"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-sw/strings.xml b/mediarouter/src/main/res/values-sw/strings.xml
new file mode 100644
index 0000000..2a7af85
--- /dev/null
+++ b/mediarouter/src/main/res/values-sw/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Mfumo"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Vifaa"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Kitufe cha kutuma"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Kitufe cha kutuma. Kimeondolewa"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Kitufe cha kutuma. Kinaunganishwa"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Kitufe cha kutuma. Kimeunganishwa"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Tuma kwenye"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Inatafuta vifaa"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ondoa"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Acha kutuma"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Funga"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Cheza"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Sitisha"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Simamisha"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Panua"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Kunja"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Sanaa ya albamu"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Kidhibiti cha sauti"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Hakuna maudhui yaliyochaguliwa"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Hakuna maelezo yaliyopatikana"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Inatuma skrini"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ta/strings.xml b/mediarouter/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..6b4f896
--- /dev/null
+++ b/mediarouter/src/main/res/values-ta/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"சிஸ்டம்"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"சாதனங்கள்"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"அலைபரப்பும் பட்டன்"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"அலைபரப்பும் பட்டன். துண்டிக்கப்பட்டது"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"அலைபரப்பும் பட்டன். இணைக்கிறது"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"அலைபரப்பும் பட்டன். இணைக்கப்பட்டது"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"இதற்கு அலைபரப்பு:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"சாதனங்களைத் தேடுகிறது"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"துண்டி"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"அலைபரப்புவதை நிறுத்து"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"மூடுவதற்கான பட்டன்"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"இயக்குவதற்கான பட்டன்"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"இடைநிறுத்துவதற்கான பட்டன்"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"நிறுத்துவதற்கான பட்டன்"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"விரிவாக்குவதற்கான பட்டன்"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"சுருக்குவதற்கான பட்டன்"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ஆல்பம் ஆர்ட்"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"ஒலியளவு ஸ்லைடர்"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"தகவல் எதுவுமில்லை"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"திரையை அலைபரப்புகிறது"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-te/strings.xml b/mediarouter/src/main/res/values-te/strings.xml
new file mode 100644
index 0000000..0d4168f
--- /dev/null
+++ b/mediarouter/src/main/res/values-te/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"సిస్టమ్"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"పరికరాలు"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Cast బటన్"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Cast బటన్. డిస్కనెక్ట్ చేయబడింది"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Cast బటన్. కనెక్ట్ చేస్తోంది"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Cast బటన్. కనెక్ట్ చేయబడింది"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"దీనికి ప్రసారం చేయండి"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"పరికరాలను కనుగొంటోంది"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"డిస్కనెక్ట్ చేయి"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"ప్రసారాన్ని ఆపివేయి"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"మూసివేయి"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"ప్లే చేయి"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"పాజ్ చేయి"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"ఆపివేయి"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"విస్తరించు"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"కుదించు"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ఆల్బమ్ ఆర్ట్"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"వాల్యూమ్ స్లయిడర్"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"మీడియా ఏదీ ఎంచుకోలేదు"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"సమాచారం అందుబాటులో లేదు"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"స్క్రీన్ను ప్రసారం చేస్తోంది"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-th/strings.xml b/mediarouter/src/main/res/values-th/strings.xml
new file mode 100644
index 0000000..b360779
--- /dev/null
+++ b/mediarouter/src/main/res/values-th/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"ระบบ"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"อุปกรณ์"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"ปุ่ม \"แคสต์\""</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"ปุ่ม \"แคสต์\" ยกเลิกการเชื่อมต่อแล้ว"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"ปุ่ม \"แคสต์\" กำลังเชื่อมต่อ"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"ปุ่ม \"แคสต์\" เชื่อมต่อแล้ว"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"แคสต์ไปยัง"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"กำลังค้นหาอุปกรณ์"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"ยกเลิกการเชื่อมต่อ"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"หยุดแคสต์"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"ปิด"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"เล่น"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"หยุดชั่วคราว"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"หยุด"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"ขยาย"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"ยุบ"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"ปกอัลบั้ม"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"แถบเลื่อนปรับระดับเสียง"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"ไม่ได้เลือกสื่อไว้"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"ไม่มีข้อมูล"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"กำลังแคสต์หน้าจอ"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-tl/strings.xml b/mediarouter/src/main/res/values-tl/strings.xml
new file mode 100644
index 0000000..4d21125
--- /dev/null
+++ b/mediarouter/src/main/res/values-tl/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"System"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Mga Device"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Button na I-cast"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Button na I-cast. Nadiskonekta"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Button na I-cast. Kumokonekta"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Button na I-cast. Nakakonekta"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"I-cast sa"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Naghahanap ng mga device"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Idiskonekta"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Ihinto ang pag-cast"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Isara"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"I-play"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"I-pause"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Ihinto"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"I-expand"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"I-collapse"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Album art"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Slider ng volume"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Walang napiling media"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Walang available na impormasyon"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ikina-cast ang screen"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-tr/strings.xml b/mediarouter/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..e44f443
--- /dev/null
+++ b/mediarouter/src/main/res/values-tr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Cihazlar"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Yayınla düğmesi"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Yayınla düğmesi. Bağlantı kesildi"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Yayınla düğmesi. Bağlanıyor"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Yayınla düğmesi. Bağlandı"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Şuraya yayınla:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Cihazlar bulunuyor"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Bağlantıyı kes"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Yayını durdur"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Kapat"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Oynat"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Duraklat"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Durdur"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Genişlet"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Daralt"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albüm kapağı"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Ses düzeyi kaydırma çubuğu"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Medya seçilmedi"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Bilgi yok"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekran yayınlanıyor"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-uk/strings.xml b/mediarouter/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000..28e09bd
--- /dev/null
+++ b/mediarouter/src/main/res/values-uk/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Система"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Пристрої"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Кнопка трансляції"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Кнопка трансляції. Від’єднано"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Кнопка трансляції. Під’єднання"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Кнопка трансляції. Під’єднано"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Транслювати на"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Пошук пристроїв"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Від’єднати"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Припинити трансляцію"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Закрити"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Відтворити"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Призупинити"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Припинити"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Розгорнути"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Згорнути"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Обкладинка альбому"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Повзунок гучності"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Не вибрано медіа"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Немає даних"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Трансляція екрана"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-ur/strings.xml b/mediarouter/src/main/res/values-ur/strings.xml
new file mode 100644
index 0000000..8c09830
--- /dev/null
+++ b/mediarouter/src/main/res/values-ur/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"سسٹم"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"آلات"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"کاسٹ کرنے کا بٹن"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"کاسٹ کرنے کا بٹن۔ غیر منسلک ہے"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"کاسٹ کرنے کا بٹن۔ منسلک ہو رہا ہے"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"کاسٹ کرنے کا بٹن۔ منسلک ہے"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"اس میں کاسٹ کریں"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"آلات تلاش کئے جا رہے ہیں"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"غیر منسلک کریں"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"کاسٹ کرنا بند کریں"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"بند کریں"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"چلائیں"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"موقوف کریں"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"روکیں"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"پھیلائیں"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"سکیڑیں"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"البم آرٹ"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"والیوم سلائیڈر"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"کوئی میڈیا منتخب نہیں ہے"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"کوئی معلومات دستیاب نہیں"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"اسکرین کاسٹ ہو رہی ہے"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-uz/strings.xml b/mediarouter/src/main/res/values-uz/strings.xml
index 0c6fbf1..2eadc9b 100644
--- a/mediarouter/src/main/res/values-uz/strings.xml
+++ b/mediarouter/src/main/res/values-uz/strings.xml
@@ -16,25 +16,25 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="mr_system_route_name" msgid="3117964881088969586">"Tizim"</string>
- <string name="mr_user_route_category_name" msgid="8236416097133080726">"Qurilmalar"</string>
- <string name="mr_button_content_description" msgid="1685185767093348095">"Translatsiya tugmasi"</string>
- <string name="mr_cast_button_disconnected" msgid="5501231066847739632">"Translatsiya tugmasi. Uzildi"</string>
- <string name="mr_cast_button_connecting" msgid="8959304318293841992">"Translatsiya tugmasi. Ulanmoqda"</string>
- <string name="mr_cast_button_connected" msgid="1350095112462806159">"Translatsiya tugmasi. Ulandi"</string>
- <string name="mr_chooser_title" msgid="7548226170787476564">"Bunga translatsiya qilish:"</string>
- <string name="mr_chooser_searching" msgid="5504553798429329689">"Qurilmalarni topish"</string>
- <string name="mr_controller_disconnect" msgid="1370654436555555647">"Uzish"</string>
- <string name="mr_controller_stop_casting" msgid="7617024847862349259">"Translatsiyani to‘xtatish"</string>
- <string name="mr_controller_close_description" msgid="5468775621814500662">"Yopish"</string>
- <string name="mr_controller_play" msgid="4443315438268112801">"Ijro"</string>
- <string name="mr_controller_pause" msgid="4701315813294065305">"Pauza"</string>
- <string name="mr_controller_stop" msgid="5106056093749454009">"To‘xtatish"</string>
- <string name="mr_controller_expand_group" msgid="2422682304043876468">"Yoyish"</string>
- <string name="mr_controller_collapse_group" msgid="5518911192681928413">"Yig‘ish"</string>
- <string name="mr_controller_album_art" msgid="5813284753012893250">"Albom muqovasi"</string>
- <string name="mr_controller_volume_slider" msgid="691656961160498512">"Tovush balandligi slayderi"</string>
- <string name="mr_controller_no_media_selected" msgid="4342878516155861006">"Multimedia tanlamagan"</string>
- <string name="mr_controller_no_info_available" msgid="7299368841849988218">"Ma’lumot yo‘q"</string>
- <string name="mr_controller_casting_screen" msgid="5286734709674025661">"Ekran namoyish qilinmoqda"</string>
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Tizim"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Qurilmalar"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Translatsiya qilish tugmasi"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Translatsiya tugmasi. Uzildi"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Translatsiya tugmasi. Ulanmoqda"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Translatsiya tugmasi. Ulandi"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Bunga translatsiya qilish:"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Qurilmalarni topish"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Uzish"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Translatsiyani to‘xtatish"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Yopish"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Ijro"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Pauza"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"To‘xtatish"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Yoyish"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Yig‘ish"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Albom muqovasi"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Tovush balandligi slayderi"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Multimedia tanlamagan"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Ma’lumot yo‘q"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Ekran namoyish qilinmoqda"</string>
</resources>
diff --git a/mediarouter/src/main/res/values-vi/strings.xml b/mediarouter/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000..d0f7311
--- /dev/null
+++ b/mediarouter/src/main/res/values-vi/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Hệ thống"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Thiết bị"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Nút truyền"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Nút truyền. Đã ngắt kết nối"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Nút truyền. Đang kết nối"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Nút truyền. Đã kết nối"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Truyền tới"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Đang tìm thiết bị"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Ngắt kết nối"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Dừng truyền"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Đóng"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Phát"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Tạm dừng"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Dừng"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Mở rộng"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Thu gọn"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Ảnh bìa album"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Thanh trượt âm lượng"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Không có phương tiện nào được chọn"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Không có thông tin nào"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Đang truyền màn hình"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-zh-rCN/strings.xml b/mediarouter/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..140c817
--- /dev/null
+++ b/mediarouter/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"系统"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"设备"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"投射按钮"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"投射按钮。已断开连接"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"投射按钮。正在连接"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"投射按钮。已连接"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"投射到"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"正在查找设备"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"断开连接"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"停止投射"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"关闭"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"播放"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"暂停"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"停止"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"展开"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"收起"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"专辑封面"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量滑块"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"未选择任何媒体内容"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"没有任何相关信息"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"正在投射屏幕"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-zh-rHK/strings.xml b/mediarouter/src/main/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..9318093
--- /dev/null
+++ b/mediarouter/src/main/res/values-zh-rHK/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"系統"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"裝置"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"投放按鈕"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"投放按鈕。解除咗連線"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"投放按鈕。連緊線"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"投放按鈕。連咗線"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"投放至"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"正在尋找裝置"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"解除連線"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"停止投放"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"閂"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"播放"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"暫停"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"停"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"展開"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"收合"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"專輯封面"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量滑桿"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"未選取任何媒體"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"沒有資料可以提供"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"正在投放畫面"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-zh-rTW/strings.xml b/mediarouter/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..bd2f9ad
--- /dev/null
+++ b/mediarouter/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"系統"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"裝置"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"投放按鈕"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"投放按鈕;已中斷連線"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"投放按鈕;連線中"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"投放按鈕;已連線"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"投放到"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"正在尋找裝置"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"中斷連線"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"停止投放"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"關閉"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"播放"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"暫停"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"停止"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"展開"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"收合"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"專輯封面"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"音量滑桿"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"未選取任何媒體"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"沒有可用的資訊"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"正在投放畫面"</string>
+</resources>
diff --git a/mediarouter/src/main/res/values-zu/strings.xml b/mediarouter/src/main/res/values-zu/strings.xml
new file mode 100644
index 0000000..e91293f
--- /dev/null
+++ b/mediarouter/src/main/res/values-zu/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="mr_system_route_name" msgid="6445173646164603280">"Isistimu"</string>
+ <string name="mr_user_route_category_name" msgid="8951247913519682277">"Amadivayisi"</string>
+ <string name="mr_button_content_description" msgid="6209940985205889239">"Inkinobho yokusakaza"</string>
+ <string name="mr_cast_button_disconnected" msgid="1214396433859225686">"Inkinobho yokusakaza. Kunqanyuliwe"</string>
+ <string name="mr_cast_button_connecting" msgid="7767160474954808770">"Inkinobho yokusakaza. Kuyaxhunywa"</string>
+ <string name="mr_cast_button_connected" msgid="7205934955575650355">"Inkinobho yokusakaza. Kuxhunyiwe"</string>
+ <string name="mr_chooser_title" msgid="1469819231928206099">"Sakaza ku-"</string>
+ <string name="mr_chooser_searching" msgid="7883700464756247478">"Ithola amadivayisi"</string>
+ <string name="mr_controller_disconnect" msgid="1224563715954797152">"Nqamula"</string>
+ <string name="mr_controller_stop_casting" msgid="6043110833085090960">"Misa ukusakaza"</string>
+ <string name="mr_controller_close_description" msgid="1404151965680505956">"Vala"</string>
+ <string name="mr_controller_play" msgid="2233159395781515552">"Dlala"</string>
+ <string name="mr_controller_pause" msgid="5465089322498973309">"Misa isikhashana"</string>
+ <string name="mr_controller_stop" msgid="6970507798830838731">"Misa"</string>
+ <string name="mr_controller_expand_group" msgid="6561849209271950311">"Nweba"</string>
+ <string name="mr_controller_collapse_group" msgid="5621264648958127139">"Goqa"</string>
+ <string name="mr_controller_album_art" msgid="8313236767081989488">"Ubuciko be-albhamu"</string>
+ <string name="mr_controller_volume_slider" msgid="390328956880221771">"Isilayida sevolumu"</string>
+ <string name="mr_controller_no_media_selected" msgid="5388112032574870059">"Ayikho imidiya ekhethiwe"</string>
+ <string name="mr_controller_no_info_available" msgid="942251150039480236">"Alukho ulwazi olutholakalayo"</string>
+ <string name="mr_controller_casting_screen" msgid="2406876321200529148">"Isikrini sokusakaza"</string>
+</resources>
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index dd9189c..8329c05 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -48,4 +48,5 @@
inceptionYear = "2017"
description = "Android Paging-Runtime"
url = SupportLibraryExtension.ARCHITECTURE_URL
+ failOnUncheckedWarnings = false
}
diff --git a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java
index f30163d..0033665 100644
--- a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java
+++ b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java
@@ -150,7 +150,7 @@
public AsyncPagedListDiffer(@NonNull RecyclerView.Adapter adapter,
@NonNull DiffUtil.ItemCallback<T> diffCallback) {
mUpdateCallback = new AdapterListUpdateCallback(adapter);
- mConfig = new AsyncDifferConfig.Builder<T>(diffCallback).build();
+ mConfig = new AsyncDifferConfig.Builder<>(diffCallback).build();
}
@SuppressWarnings("WeakerAccess")
@@ -227,6 +227,7 @@
*
* @param pagedList The new PagedList.
*/
+ @SuppressWarnings("ReferenceEquality")
public void submitList(final PagedList<T> pagedList) {
if (pagedList != null) {
if (mPagedList == null && mSnapshot == null) {
diff --git a/paging/rxjava2/build.gradle b/paging/rxjava2/build.gradle
index f4c5308..2fd8caf 100644
--- a/paging/rxjava2/build.gradle
+++ b/paging/rxjava2/build.gradle
@@ -45,4 +45,5 @@
inceptionYear = "2018"
description = "Android Paging RXJava2"
url = SupportLibraryExtension.ARCHITECTURE_URL
+ failOnUncheckedWarnings = false
}
diff --git a/preference/build.gradle b/preference/build.gradle
index b7c6872..8518300 100644
--- a/preference/build.gradle
+++ b/preference/build.gradle
@@ -55,4 +55,6 @@
mavenGroup = LibraryGroups.PREFERENCE
inceptionYear = "2015"
description = "Android Support Preference v7"
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/preference/res/values-af/strings.xml b/preference/res/values-af/strings.xml
new file mode 100644
index 0000000..17c2037
--- /dev/null
+++ b/preference/res/values-af/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AAN"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"AF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Gevorderd"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-am/strings.xml b/preference/res/values-am/strings.xml
new file mode 100644
index 0000000..052425c
--- /dev/null
+++ b/preference/res/values-am/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"በርቷል"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ቅናሽ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"የላቀ"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>፣ <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ar/strings.xml b/preference/res/values-ar/strings.xml
new file mode 100644
index 0000000..1e5515d
--- /dev/null
+++ b/preference/res/values-ar/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"تفعيل"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"إيقاف"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"إعدادات متقدمة"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-az/strings.xml b/preference/res/values-az/strings.xml
index 1b208c8..978b862 100644
--- a/preference/res/values-az/strings.xml
+++ b/preference/res/values-az/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"AKTİV"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"DEAKTİV"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Qabaqcıl"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"AKTİV"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DEAKTİV"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Qabaqcıl"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-b+sr+Latn/strings.xml b/preference/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..61c784a
--- /dev/null
+++ b/preference/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"UKLJUČENO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ISKLJUČENO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Napredno"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-be/strings.xml b/preference/res/values-be/strings.xml
new file mode 100644
index 0000000..8ebdeaf
--- /dev/null
+++ b/preference/res/values-be/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"УКЛ."</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ВЫКЛ."</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Высокая"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-bg/strings.xml b/preference/res/values-bg/strings.xml
new file mode 100644
index 0000000..e2e9544
--- /dev/null
+++ b/preference/res/values-bg/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ВКЛ."</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ИЗКЛ."</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Разширени"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-bn/strings.xml b/preference/res/values-bn/strings.xml
new file mode 100644
index 0000000..a17e22a
--- /dev/null
+++ b/preference/res/values-bn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"চালু"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"বন্ধ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"উন্নত"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-bs/strings.xml b/preference/res/values-bs/strings.xml
new file mode 100644
index 0000000..61c784a
--- /dev/null
+++ b/preference/res/values-bs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"UKLJUČENO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ISKLJUČENO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Napredno"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ca/strings.xml b/preference/res/values-ca/strings.xml
new file mode 100644
index 0000000..56e5c66
--- /dev/null
+++ b/preference/res/values-ca/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVAT"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVAT"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Opcions avançades"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-cs/strings.xml b/preference/res/values-cs/strings.xml
new file mode 100644
index 0000000..5865c0b
--- /dev/null
+++ b/preference/res/values-cs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ZAP"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"VYP"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Rozšířené"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-da/strings.xml b/preference/res/values-da/strings.xml
new file mode 100644
index 0000000..da2532f
--- /dev/null
+++ b/preference/res/values-da/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"TIL"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"FRA"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avanceret"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-de/strings.xml b/preference/res/values-de/strings.xml
new file mode 100644
index 0000000..5b0be51
--- /dev/null
+++ b/preference/res/values-de/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AN"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"AUS"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Erweitert"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-el/strings.xml b/preference/res/values-el/strings.xml
new file mode 100644
index 0000000..59ba395
--- /dev/null
+++ b/preference/res/values-el/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Σύνθετες"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-en-rAU/strings.xml b/preference/res/values-en-rAU/strings.xml
index c8d1681..dd3e15f 100644
--- a/preference/res/values-en-rAU/strings.xml
+++ b/preference/res/values-en-rAU/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"ON"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"OFF"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Advanced"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-en-rCA/strings.xml b/preference/res/values-en-rCA/strings.xml
index c8d1681..dd3e15f 100644
--- a/preference/res/values-en-rCA/strings.xml
+++ b/preference/res/values-en-rCA/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"ON"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"OFF"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Advanced"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-en-rGB/strings.xml b/preference/res/values-en-rGB/strings.xml
index c8d1681..dd3e15f 100644
--- a/preference/res/values-en-rGB/strings.xml
+++ b/preference/res/values-en-rGB/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"ON"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"OFF"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Advanced"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-en-rIN/strings.xml b/preference/res/values-en-rIN/strings.xml
index c8d1681..dd3e15f 100644
--- a/preference/res/values-en-rIN/strings.xml
+++ b/preference/res/values-en-rIN/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"ON"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"OFF"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Advanced"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-en-rXC/strings.xml b/preference/res/values-en-rXC/strings.xml
index 96219e7..3f4c7a0 100644
--- a/preference/res/values-en-rXC/strings.xml
+++ b/preference/res/values-en-rXC/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"ON"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"OFF"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Advanced"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-es-rUS/strings.xml b/preference/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..3911ab9
--- /dev/null
+++ b/preference/res/values-es-rUS/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVADO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVADO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avanzado"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-es/strings.xml b/preference/res/values-es/strings.xml
new file mode 100644
index 0000000..3911ab9
--- /dev/null
+++ b/preference/res/values-es/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVADO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVADO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avanzado"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-et/strings.xml b/preference/res/values-et/strings.xml
new file mode 100644
index 0000000..9fa4f4f
--- /dev/null
+++ b/preference/res/values-et/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"SEES"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"VÄLJAS"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Täpsemad"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-eu/strings.xml b/preference/res/values-eu/strings.xml
new file mode 100644
index 0000000..6718992
--- /dev/null
+++ b/preference/res/values-eu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AKTIBATUTA"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESAKTIBATUTA"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Aurreratua"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-fa/strings.xml b/preference/res/values-fa/strings.xml
new file mode 100644
index 0000000..86e9f30
--- /dev/null
+++ b/preference/res/values-fa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"روشن"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"خاموش"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"پیشرفته"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-fi/strings.xml b/preference/res/values-fi/strings.xml
new file mode 100644
index 0000000..cec0857
--- /dev/null
+++ b/preference/res/values-fi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"PÄÄLLÄ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"POIS PÄÄLTÄ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Lisätiedot"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-fr-rCA/strings.xml b/preference/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..db4c2b5
--- /dev/null
+++ b/preference/res/values-fr-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVÉ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DÉSACTIVÉ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avancé"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-fr/strings.xml b/preference/res/values-fr/strings.xml
new file mode 100644
index 0000000..b5cca98
--- /dev/null
+++ b/preference/res/values-fr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVÉ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DÉSACTIVÉ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Options avancées"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-gl/strings.xml b/preference/res/values-gl/strings.xml
new file mode 100644
index 0000000..3911ab9
--- /dev/null
+++ b/preference/res/values-gl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVADO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESACTIVADO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avanzado"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-gu/strings.xml b/preference/res/values-gu/strings.xml
new file mode 100644
index 0000000..468fd2c
--- /dev/null
+++ b/preference/res/values-gu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ચાલુ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"બંધ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"વિગતવાર"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-hi/strings.xml b/preference/res/values-hi/strings.xml
new file mode 100644
index 0000000..dcfb766
--- /dev/null
+++ b/preference/res/values-hi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"चालू"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"बंद"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"बेहतर विकल्प"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-hr/strings.xml b/preference/res/values-hr/strings.xml
new file mode 100644
index 0000000..61c784a
--- /dev/null
+++ b/preference/res/values-hr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"UKLJUČENO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ISKLJUČENO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Napredno"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-hu/strings.xml b/preference/res/values-hu/strings.xml
new file mode 100644
index 0000000..85f80aa
--- /dev/null
+++ b/preference/res/values-hu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"BE"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"KI"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Speciális"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-hy/strings.xml b/preference/res/values-hy/strings.xml
new file mode 100644
index 0000000..06f9d22
--- /dev/null
+++ b/preference/res/values-hy/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ՄԻԱՑՎԱԾ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ԱՆՋԱՏԱԾ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Լրացուցիչ"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-in/strings.xml b/preference/res/values-in/strings.xml
new file mode 100644
index 0000000..e17c251
--- /dev/null
+++ b/preference/res/values-in/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AKTIF"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"NONAKTIF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Lanjutan"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-is/strings.xml b/preference/res/values-is/strings.xml
new file mode 100644
index 0000000..361d1c3
--- /dev/null
+++ b/preference/res/values-is/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"KVEIKT"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"SLÖKKT"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Ítarlegt"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-it/strings.xml b/preference/res/values-it/strings.xml
new file mode 100644
index 0000000..2514600
--- /dev/null
+++ b/preference/res/values-it/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avanzate"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-iw/strings.xml b/preference/res/values-iw/strings.xml
new file mode 100644
index 0000000..6ca15e5
--- /dev/null
+++ b/preference/res/values-iw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"מופעל"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"כבוי"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"מתקדם"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ja/strings.xml b/preference/res/values-ja/strings.xml
new file mode 100644
index 0000000..2d599d3
--- /dev/null
+++ b/preference/res/values-ja/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"詳細設定"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>、<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ka/strings.xml b/preference/res/values-ka/strings.xml
new file mode 100644
index 0000000..21b8246
--- /dev/null
+++ b/preference/res/values-ka/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ჩართული"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"გამორთული"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"დამატებით"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-kk/strings.xml b/preference/res/values-kk/strings.xml
new file mode 100644
index 0000000..ebbba78
--- /dev/null
+++ b/preference/res/values-kk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ҚОСУЛЫ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ӨШІРУЛІ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Қосымша"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-km/strings.xml b/preference/res/values-km/strings.xml
new file mode 100644
index 0000000..d7cb942
--- /dev/null
+++ b/preference/res/values-km/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"បើក"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"បិទ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"កម្រិតខ្ពស់"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-kn/strings.xml b/preference/res/values-kn/strings.xml
new file mode 100644
index 0000000..9ce1917
--- /dev/null
+++ b/preference/res/values-kn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ಆನ್"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ಆಫ್"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"ಸುಧಾರಿತ"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ko/strings.xml b/preference/res/values-ko/strings.xml
new file mode 100644
index 0000000..ab1f380
--- /dev/null
+++ b/preference/res/values-ko/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"사용"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"사용 안함"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"고급"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ky/strings.xml b/preference/res/values-ky/strings.xml
new file mode 100644
index 0000000..257c6d5
--- /dev/null
+++ b/preference/res/values-ky/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"КҮЙҮК"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ӨЧҮК"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Өркүндөтүлгөн"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-lo/strings.xml b/preference/res/values-lo/strings.xml
new file mode 100644
index 0000000..f4c1e2d
--- /dev/null
+++ b/preference/res/values-lo/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ເປີດ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ປິດ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"ຂັ້ນສູງ"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-lt/strings.xml b/preference/res/values-lt/strings.xml
new file mode 100644
index 0000000..ef1bfd6
--- /dev/null
+++ b/preference/res/values-lt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"Įjungta"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"Išjungta"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Išplėstinės"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-lv/strings.xml b/preference/res/values-lv/strings.xml
new file mode 100644
index 0000000..e4890b1
--- /dev/null
+++ b/preference/res/values-lv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"IESLĒGTS"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"IZSLĒGTS"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Papildu"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-mk/strings.xml b/preference/res/values-mk/strings.xml
new file mode 100644
index 0000000..f276876
--- /dev/null
+++ b/preference/res/values-mk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ВКЛУЧЕНО"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ИСКЛУЧЕНО"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Напредно"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ml/strings.xml b/preference/res/values-ml/strings.xml
new file mode 100644
index 0000000..83d1125
--- /dev/null
+++ b/preference/res/values-ml/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ഓൺ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ഓഫ്"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"വിപുലമായത്"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-mn/strings.xml b/preference/res/values-mn/strings.xml
new file mode 100644
index 0000000..2d20950
--- /dev/null
+++ b/preference/res/values-mn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"АСААЛТТАЙ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"УНТРААТАЙ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Нарийвчилсан"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-mr/strings.xml b/preference/res/values-mr/strings.xml
new file mode 100644
index 0000000..1e492dd
--- /dev/null
+++ b/preference/res/values-mr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"चालू"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"बंद"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"प्रगत"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ms/strings.xml b/preference/res/values-ms/strings.xml
new file mode 100644
index 0000000..1601d8a
--- /dev/null
+++ b/preference/res/values-ms/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"HIDUP"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"MATI"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Lanjutan"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-my/strings.xml b/preference/res/values-my/strings.xml
new file mode 100644
index 0000000..77237bc
--- /dev/null
+++ b/preference/res/values-my/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ဖွင့်ရန်"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ပိတ်ရန်"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"အဆင့်မြင့်"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>၊ <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-nb/strings.xml b/preference/res/values-nb/strings.xml
new file mode 100644
index 0000000..d5c814b
--- /dev/null
+++ b/preference/res/values-nb/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"PÅ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"AV"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avansert"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ne/strings.xml b/preference/res/values-ne/strings.xml
new file mode 100644
index 0000000..1da1f25
--- /dev/null
+++ b/preference/res/values-ne/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"सक्रिय छ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"निष्क्रिय छ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"उन्नत"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-nl/strings.xml b/preference/res/values-nl/strings.xml
new file mode 100644
index 0000000..dc84ab8
--- /dev/null
+++ b/preference/res/values-nl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AAN"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"UIT"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Geavanceerd"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-pa/strings.xml b/preference/res/values-pa/strings.xml
new file mode 100644
index 0000000..29471c3
--- /dev/null
+++ b/preference/res/values-pa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ਚਾਲੂ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ਬੰਦ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"ਉੱਨਤ"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-pl/strings.xml b/preference/res/values-pl/strings.xml
new file mode 100644
index 0000000..ef7bbf8
--- /dev/null
+++ b/preference/res/values-pl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"WŁ."</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"WYŁ."</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Zaawansowane"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-pt-rBR/strings.xml b/preference/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..433e8e3
--- /dev/null
+++ b/preference/res/values-pt-rBR/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ATIVADO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESATIVADO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avançado"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-pt-rPT/strings.xml b/preference/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..4f296f6
--- /dev/null
+++ b/preference/res/values-pt-rPT/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ATIVADA"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESATIVADA"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avançadas"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-pt/strings.xml b/preference/res/values-pt/strings.xml
new file mode 100644
index 0000000..433e8e3
--- /dev/null
+++ b/preference/res/values-pt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ATIVADO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DESATIVADO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avançado"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ro/strings.xml b/preference/res/values-ro/strings.xml
new file mode 100644
index 0000000..1353a6f
--- /dev/null
+++ b/preference/res/values-ro/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ACTIVAT"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"DEZACTIVAT"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avansat"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ru/strings.xml b/preference/res/values-ru/strings.xml
new file mode 100644
index 0000000..8449700
--- /dev/null
+++ b/preference/res/values-ru/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ВКЛ."</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ВЫКЛ."</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Дополнительно"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-si/strings.xml b/preference/res/values-si/strings.xml
new file mode 100644
index 0000000..27bf118
--- /dev/null
+++ b/preference/res/values-si/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ක්රියාත්මකයි"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ක්රියාවිරහිතයි"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"උසස්"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-sk/strings.xml b/preference/res/values-sk/strings.xml
new file mode 100644
index 0000000..a087a8b
--- /dev/null
+++ b/preference/res/values-sk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ZAP."</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"VYP."</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Rozšírené"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-sl/strings.xml b/preference/res/values-sl/strings.xml
new file mode 100644
index 0000000..887c1b1
--- /dev/null
+++ b/preference/res/values-sl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"VKLOPLJENO"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"IZKLOPLJENO"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Dodatno"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-sq/strings.xml b/preference/res/values-sq/strings.xml
new file mode 100644
index 0000000..f2f5b77
--- /dev/null
+++ b/preference/res/values-sq/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AKTIV"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"JOAKTIV"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Të përparuara"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-sr/strings.xml b/preference/res/values-sr/strings.xml
new file mode 100644
index 0000000..322ace5
--- /dev/null
+++ b/preference/res/values-sr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"УКЉУЧЕНО"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ИСКЉУЧЕНО"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Напредно"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-sv/strings.xml b/preference/res/values-sv/strings.xml
new file mode 100644
index 0000000..c689ea1
--- /dev/null
+++ b/preference/res/values-sv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"PÅ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"AV"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Avancerat"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-sw/strings.xml b/preference/res/values-sw/strings.xml
new file mode 100644
index 0000000..9010663
--- /dev/null
+++ b/preference/res/values-sw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"IMEWASHWA"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"IMEZIMWA"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Mipangilio ya Kina"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ta/strings.xml b/preference/res/values-ta/strings.xml
new file mode 100644
index 0000000..9fc536d
--- /dev/null
+++ b/preference/res/values-ta/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ஆன் செய்"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ஆஃப் செய்"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"மேம்பட்டது"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-te/strings.xml b/preference/res/values-te/strings.xml
new file mode 100644
index 0000000..7277c76
--- /dev/null
+++ b/preference/res/values-te/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"ఆన్"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ఆఫ్"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"అధునాతనం"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-th/strings.xml b/preference/res/values-th/strings.xml
new file mode 100644
index 0000000..90a5433
--- /dev/null
+++ b/preference/res/values-th/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"เปิด"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ปิด"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"ขั้นสูง"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g> <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-tl/strings.xml b/preference/res/values-tl/strings.xml
new file mode 100644
index 0000000..5b6885b
--- /dev/null
+++ b/preference/res/values-tl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"NAKA-ON"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"NAKA-OFF"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Advanced"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-tr/strings.xml b/preference/res/values-tr/strings.xml
new file mode 100644
index 0000000..fa66179
--- /dev/null
+++ b/preference/res/values-tr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"AÇIK"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"KAPALI"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Gelişmiş"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-uk/strings.xml b/preference/res/values-uk/strings.xml
new file mode 100644
index 0000000..47280c3
--- /dev/null
+++ b/preference/res/values-uk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"УВІМКНЕНО"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"ВИМКНЕНО"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Додатково"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-ur/strings.xml b/preference/res/values-ur/strings.xml
new file mode 100644
index 0000000..c304b12
--- /dev/null
+++ b/preference/res/values-ur/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"آن"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"آف"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"جدید ترین"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>، <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-uz/strings.xml b/preference/res/values-uz/strings.xml
index cdf990b..6730b74 100644
--- a/preference/res/values-uz/strings.xml
+++ b/preference/res/values-uz/strings.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="v7_preference_on" msgid="27351710992731591">"YONIQ"</string>
- <string name="v7_preference_off" msgid="5138405918326871307">"O‘CHIQ"</string>
- <string name="expand_button_title" msgid="1234962710353108940">"Kengaytirilgan"</string>
- <string name="summary_collapsed_preference_list" msgid="5190123168583152844">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+ <string name="v7_preference_on" msgid="7922757586228621900">"YONIQ"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"O‘CHIQ"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Ekspert"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
</resources>
diff --git a/preference/res/values-vi/strings.xml b/preference/res/values-vi/strings.xml
new file mode 100644
index 0000000..d8ea12b
--- /dev/null
+++ b/preference/res/values-vi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"BẬT"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"TẮT"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Nâng cao"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-zh-rCN/strings.xml b/preference/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..3f91ed6
--- /dev/null
+++ b/preference/res/values-zh-rCN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"开启"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"关闭"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"高级"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"当前显示了 <xliff:g id="CURRENT_ITEMS">%1$s</xliff:g> 项(已添加 <xliff:g id="ADDED_ITEMS">%2$s</xliff:g> 项)"</string>
+</resources>
diff --git a/preference/res/values-zh-rHK/strings.xml b/preference/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..fe64c50
--- /dev/null
+++ b/preference/res/values-zh-rHK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"開啟"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"關閉"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"進階"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>,<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-zh-rTW/strings.xml b/preference/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..fe64c50
--- /dev/null
+++ b/preference/res/values-zh-rTW/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"開啟"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"關閉"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"進階"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>,<xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/preference/res/values-zu/strings.xml b/preference/res/values-zu/strings.xml
new file mode 100644
index 0000000..dab4cba
--- /dev/null
+++ b/preference/res/values-zu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="v7_preference_on" msgid="7922757586228621900">"VULA"</string>
+ <string name="v7_preference_off" msgid="2082379519172883894">"VALA"</string>
+ <string name="expand_button_title" msgid="3265458434114353660">"Okuthuthukisiwe"</string>
+ <string name="summary_collapsed_preference_list" msgid="5255557321652385027">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
+</resources>
diff --git a/print/build.gradle b/print/build.gradle
index 7901514..05919df 100644
--- a/print/build.gradle
+++ b/print/build.gradle
@@ -16,4 +16,5 @@
mavenGroup = LibraryGroups.PRINT
inceptionYear = "2018"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnDeprecationWarnings = false
}
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index 84d0445..684726e 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -17,4 +17,5 @@
inceptionYear = "2015"
description = "Android Support Recommendation"
minSdkVersion = 21
+ failOnDeprecationWarnings = false
}
diff --git a/recyclerview-selection/build.gradle b/recyclerview-selection/build.gradle
index b467e48..dcda345 100644
--- a/recyclerview-selection/build.gradle
+++ b/recyclerview-selection/build.gradle
@@ -41,4 +41,6 @@
mavenGroup = LibraryGroups.RECYCLERVIEW
inceptionYear = "2017"
description = "Library providing item selection framework for RecyclerView. Support for touch based and band selection is provided."
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/samples/SupportMediaDemos/build.gradle b/samples/SupportMediaDemos/build.gradle
index bf23177..fecf2a5 100644
--- a/samples/SupportMediaDemos/build.gradle
+++ b/samples/SupportMediaDemos/build.gradle
@@ -25,7 +25,7 @@
android {
defaultConfig {
- minSdkVersion 19
- targetSdkVersion 26
+ minSdkVersion = 19
+ targetSdkVersion = 26
}
}
diff --git a/samples/SupportMediaDemos/src/main/AndroidManifest.xml b/samples/SupportMediaDemos/src/main/AndroidManifest.xml
index 267eafd..5348161 100644
--- a/samples/SupportMediaDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportMediaDemos/src/main/AndroidManifest.xml
@@ -15,7 +15,11 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
package="com.example.androidx.media">
+
+ <uses-sdk tools:overrideLibrary="androidx.media.widget" />
+
<application android:label="Video View Test">
<!-- Video Selection Activity -->
diff --git a/samples/SupportMediaDemos/src/main/java/com/example/androidx/media/VideoViewTest.java b/samples/SupportMediaDemos/src/main/java/com/example/androidx/media/VideoViewTest.java
index d640303..0c10b01 100644
--- a/samples/SupportMediaDemos/src/main/java/com/example/androidx/media/VideoViewTest.java
+++ b/samples/SupportMediaDemos/src/main/java/com/example/androidx/media/VideoViewTest.java
@@ -29,6 +29,7 @@
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -71,6 +72,7 @@
setContentView(R.layout.video_activity);
mVideoView = findViewById(R.id.video_view);
+ mVideoView.setActivity(this);
String errorString = null;
Intent intent = getIntent();
@@ -82,12 +84,11 @@
if (mUseTextureView) {
mVideoView.setViewType(VideoView2.VIEW_TYPE_TEXTUREVIEW);
}
-
- mVideoView.setFullScreenRequestListener(new FullScreenRequestListener());
mVideoView.setVideoUri(contentUri);
mMediaControlView = new MediaControlView2(this);
mVideoView.setMediaControlView2(mMediaControlView, 2000);
+ mMediaControlView.setFullScreenRequestListener(new FullScreenRequestListener());
}
if (errorString != null) {
showErrorDialog(errorString);
@@ -179,7 +180,8 @@
}
};
- private class FullScreenRequestListener implements VideoView2.OnFullScreenRequestListener {
+ private class FullScreenRequestListener
+ implements MediaControlView2.OnFullScreenRequestListener {
@Override
public void onFullScreenRequest(View view, boolean fullScreen) {
// TODO: Remove bottom controls after adding back button functionality.
@@ -223,6 +225,7 @@
public static class MyVideoView extends VideoView2 {
private float mDX;
private float mDY;
+ private Activity mActivity;
public MyVideoView(Context context) {
super(context);
@@ -255,6 +258,18 @@
}
return super.onTouchEvent(ev);
}
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
+ mActivity.finish();
+ }
+ return true;
+ }
+
+ public void setActivity(Activity activity) {
+ mActivity = activity;
+ }
}
@Override
diff --git a/samples/SupportSliceDemos/src/main/AndroidManifest.xml b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
index 355a77a..4d43211 100644
--- a/samples/SupportSliceDemos/src/main/AndroidManifest.xml
+++ b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
@@ -48,6 +48,7 @@
<provider android:authorities="com.example.androidx.slice.demos"
android:name=".SampleSliceProvider"
+ android:exported="true"
android:grantUriPermissions="true">
<intent-filter>
<action android:name="androidx.intent.SLICE_ACTION"/>
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
index 4facfb3..622f047 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -16,13 +16,14 @@
package com.example.androidx.slice.demos;
+import static androidx.slice.core.SliceHints.INFINITY;
+
import static com.example.androidx.slice.demos.SampleSliceProvider.URI_PATHS;
import static com.example.androidx.slice.demos.SampleSliceProvider.getUri;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
@@ -48,6 +49,7 @@
import androidx.lifecycle.LiveData;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
import androidx.slice.widget.EventInfo;
import androidx.slice.widget.SliceLiveData;
import androidx.slice.widget.SliceView;
@@ -130,7 +132,6 @@
mSearchView.setQuery(savedInstanceState.getString("SELECTED_QUERY"), true);
}
- grantPackage(getPackageName());
// TODO: Listen for changes.
updateAvailableSlices();
if (TEST_INTENT) {
@@ -146,7 +147,6 @@
mTypeMenu.add("Shortcut");
mTypeMenu.add("Small");
mTypeMenu.add("Large");
- menu.add("Auth");
super.onCreateOptionsMenu(menu);
return true;
}
@@ -154,9 +154,6 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getTitle().toString()) {
- case "Auth":
- authAllSlices();
- return true;
case "Shortcut":
mTypeMenu.setIcon(R.drawable.ic_shortcut);
mSelectedMode = SliceView.MODE_SHORTCUT;
@@ -183,21 +180,6 @@
outState.putString("SELECTED_QUERY", mSearchView.getQuery().toString());
}
- private void authAllSlices() {
- List<ApplicationInfo> packages = getPackageManager().getInstalledApplications(0);
- for (ApplicationInfo info : packages) {
- grantPackage(info.packageName);
- }
- }
-
- private void grantPackage(String packageName) {
- for (int i = 0; i < URI_PATHS.length; i++) {
- grantUriPermission(packageName, getUri(URI_PATHS[i], getApplicationContext()),
- Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- }
- }
-
private void updateAvailableSlices() {
mSliceUris.clear();
List<PackageInfo> packageInfos = getPackageManager()
@@ -239,7 +221,17 @@
mContainer.addView(v);
mSliceLiveData = SliceLiveData.fromUri(this, uri);
v.setMode(mSelectedMode);
- mSliceLiveData.observe(this, v);
+ mSliceLiveData.observe(this, slice -> {
+ v.setSlice(slice);
+ SliceMetadata metadata = SliceMetadata.from(this, slice);
+ long expiry = metadata.getExpiry();
+ if (expiry != INFINITY) {
+ // Shows the updated text after the TTL expires.
+ v.postDelayed(() -> v.setSlice(slice),
+ expiry - System.currentTimeMillis() + 15);
+ }
+ });
+ mSliceLiveData.observe(this, slice -> Log.d(TAG, "Slice: " + slice));
} else {
Log.w(TAG, "Invalid uri, skipping slice: " + uri);
}
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 73d0568..91c7599 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -36,4 +36,6 @@
inceptionYear = "2017"
description = "A set of builders to create templates using SliceProvider APIs"
minSdkVersion = 19
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
index cb17394..0530edd 100644
--- a/slices/core/build.gradle
+++ b/slices/core/build.gradle
@@ -40,4 +40,6 @@
inceptionYear = "2017"
description = "The slices core library provides utilities for the slices view and provider libraries"
minSdkVersion = 19
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/slices/core/src/androidTest/java/androidx/slice/SliceTest.java b/slices/core/src/androidTest/java/androidx/slice/SliceTest.java
index 041c8fe..e092c97 100644
--- a/slices/core/src/androidTest/java/androidx/slice/SliceTest.java
+++ b/slices/core/src/androidTest/java/androidx/slice/SliceTest.java
@@ -23,9 +23,9 @@
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static android.app.slice.SliceProvider.SLICE_TYPE;
import static org.junit.Assert.assertEquals;
@@ -184,7 +184,7 @@
assertEquals(1, s.getItems().size());
SliceItem item = s.getItems().get(0);
- assertEquals(FORMAT_TIMESTAMP, item.getFormat());
+ assertEquals(FORMAT_LONG, item.getFormat());
assertEquals(43, item.getTimestamp());
}
diff --git a/slices/core/src/main/java/androidx/slice/Slice.java b/slices/core/src/main/java/androidx/slice/Slice.java
index d18ef23..aa077cb 100644
--- a/slices/core/src/main/java/androidx/slice/Slice.java
+++ b/slices/core/src/main/java/androidx/slice/Slice.java
@@ -35,7 +35,6 @@
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static androidx.slice.SliceConvert.unwrap;
import static androidx.slice.core.SliceHints.HINT_KEYWORDS;
@@ -388,7 +387,7 @@
}
/**
- * Add a timestamp to the slice being constructed
+ * Add a long to the slice being constructed
* @param subType Optional template-specific type information
* @see {@link SliceItem#getSubType()}
*/
@@ -399,6 +398,16 @@
}
/**
+ * Add a long to the slice being constructed
+ * @param subType Optional template-specific type information
+ * @see {@link SliceItem#getSubType()}
+ */
+ public Slice.Builder addLong(long time, @Nullable String subType,
+ @SliceHint List<String> hints) {
+ return addLong(time, subType, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* Add a timestamp to the slice being constructed
* @param subType Optional template-specific type information
* @see {@link SliceItem#getSubType()}
@@ -407,7 +416,7 @@
@Deprecated
public Slice.Builder addTimestamp(long time, @Nullable String subType,
@SliceHint String... hints) {
- mItems.add(new SliceItem(time, FORMAT_TIMESTAMP, subType, hints));
+ mItems.add(new SliceItem(time, FORMAT_LONG, subType, hints));
return this;
}
@@ -455,20 +464,37 @@
public String toString(String indent) {
StringBuilder sb = new StringBuilder();
sb.append(indent);
- sb.append("slice: ");
- sb.append("\n");
- indent += " ";
+ sb.append("slice ");
+ addHints(sb, mHints);
+ sb.append("{\n");
+ String nextIndent = indent + " ";
for (int i = 0; i < mItems.length; i++) {
SliceItem item = mItems[i];
- sb.append(item.toString(indent));
- if (!FORMAT_SLICE.equals(item.getFormat())) {
- sb.append("\n");
- }
+ sb.append(item.toString(nextIndent));
}
+ sb.append(indent);
+ sb.append("}");
return sb.toString();
}
/**
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY)
+ public static void addHints(StringBuilder sb, String[] hints) {
+ if (hints == null || hints.length == 0) return;
+
+ sb.append("(");
+ int end = hints.length - 1;
+ for (int i = 0; i < end; i++) {
+ sb.append(hints[i]);
+ sb.append(", ");
+ }
+ sb.append(hints[end]);
+ sb.append(") ");
+ }
+
+ /**
* Turns a slice Uri into slice content.
*
* @hide
@@ -493,6 +519,6 @@
private static Slice callBindSlice(Context context, Uri uri,
Set<SliceSpec> supportedSpecs) {
return SliceConvert.wrap(context.getSystemService(SliceManager.class)
- .bindSlice(uri, new ArrayList<>(unwrap(supportedSpecs))));
+ .bindSlice(uri, unwrap(supportedSpecs)));
}
}
diff --git a/slices/core/src/main/java/androidx/slice/SliceConvert.java b/slices/core/src/main/java/androidx/slice/SliceConvert.java
index 73ff368..fea5b4c 100644
--- a/slices/core/src/main/java/androidx/slice/SliceConvert.java
+++ b/slices/core/src/main/java/androidx/slice/SliceConvert.java
@@ -19,17 +19,16 @@
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.collection.ArraySet;
import androidx.core.graphics.drawable.IconCompat;
-import java.util.List;
import java.util.Set;
/**
@@ -43,9 +42,8 @@
*/
public static android.app.slice.Slice unwrap(androidx.slice.Slice slice) {
android.app.slice.Slice.Builder builder = new android.app.slice.Slice.Builder(
- slice.getUri());
+ slice.getUri(), unwrap(slice.getSpec()));
builder.addHints(slice.getHints());
- builder.setSpec(unwrap(slice.getSpec()));
for (androidx.slice.SliceItem item : slice.getItems()) {
switch (item.getFormat()) {
case FORMAT_SLICE:
@@ -67,8 +65,8 @@
case FORMAT_INT:
builder.addInt(item.getInt(), item.getSubType(), item.getHints());
break;
- case FORMAT_TIMESTAMP:
- builder.addTimestamp(item.getTimestamp(), item.getSubType(), item.getHints());
+ case FORMAT_LONG:
+ builder.addLong(item.getLong(), item.getSubType(), item.getHints());
break;
}
}
@@ -119,8 +117,8 @@
case FORMAT_INT:
builder.addInt(item.getInt(), item.getSubType(), item.getHints());
break;
- case FORMAT_TIMESTAMP:
- builder.addTimestamp(item.getTimestamp(), item.getSubType(), item.getHints());
+ case FORMAT_LONG:
+ builder.addLong(item.getLong(), item.getSubType(), item.getHints());
break;
}
}
@@ -137,7 +135,7 @@
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public static Set<androidx.slice.SliceSpec> wrap(
- List<android.app.slice.SliceSpec> supportedSpecs) {
+ Set<android.app.slice.SliceSpec> supportedSpecs) {
Set<androidx.slice.SliceSpec> ret = new ArraySet<>();
for (android.app.slice.SliceSpec spec : supportedSpecs) {
ret.add(wrap(spec));
diff --git a/slices/core/src/main/java/androidx/slice/SliceItem.java b/slices/core/src/main/java/androidx/slice/SliceItem.java
index 004e51d..f6ae848 100644
--- a/slices/core/src/main/java/androidx/slice/SliceItem.java
+++ b/slices/core/src/main/java/androidx/slice/SliceItem.java
@@ -23,7 +23,8 @@
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import static androidx.slice.Slice.addHints;
import android.app.PendingIntent;
import android.app.RemoteInput;
@@ -57,7 +58,7 @@
* <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_INT}</li>
- * <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_LONG}</li>
* <p>
* The hints that a {@link SliceItem} are a set of strings which annotate
* the content. The hints that are guaranteed to be understood by the system
@@ -76,7 +77,7 @@
*/
@RestrictTo(Scope.LIBRARY)
@StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_INT,
- FORMAT_TIMESTAMP, FORMAT_REMOTE_INPUT, FORMAT_LONG})
+ FORMAT_LONG, FORMAT_REMOTE_INPUT, FORMAT_LONG})
public @interface SliceType {
}
@@ -162,7 +163,7 @@
* <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_INT}</li>
- * <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_LONG}</li>
* <li>{@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}</li>
* @see #getSubType() ()
*/
@@ -345,7 +346,7 @@
case FORMAT_INT:
dest.putInt(OBJ, (Integer) mObj);
break;
- case FORMAT_TIMESTAMP:
+ case FORMAT_LONG:
dest.putLong(OBJ, (Long) mObj);
break;
}
@@ -367,7 +368,7 @@
new Slice(in.getBundle(OBJ_2)));
case FORMAT_INT:
return in.getInt(OBJ);
- case FORMAT_TIMESTAMP:
+ case FORMAT_LONG:
return in.getLong(OBJ);
}
throw new RuntimeException("Unsupported type " + type);
@@ -389,8 +390,8 @@
return "Action";
case FORMAT_INT:
return "Int";
- case FORMAT_TIMESTAMP:
- return "Timestamp";
+ case FORMAT_LONG:
+ return "Long";
case FORMAT_REMOTE_INPUT:
return "RemoteInput";
}
@@ -412,36 +413,35 @@
@RestrictTo(Scope.LIBRARY)
public String toString(String indent) {
StringBuilder sb = new StringBuilder();
- if (!FORMAT_SLICE.equals(getFormat())) {
- sb.append(indent);
- sb.append(getFormat());
- sb.append(": ");
- }
switch (getFormat()) {
case FORMAT_SLICE:
sb.append(getSlice().toString(indent));
break;
case FORMAT_ACTION:
- sb.append(getAction());
- sb.append("\n");
+ sb.append(indent).append(getAction()).append(",\n");
sb.append(getSlice().toString(indent));
break;
case FORMAT_TEXT:
- sb.append(getText());
+ sb.append(indent).append('"').append(getText()).append('"');
break;
case FORMAT_IMAGE:
- sb.append(getIcon());
+ sb.append(indent).append(getIcon());
break;
case FORMAT_INT:
- sb.append(getInt());
+ sb.append(indent).append(getInt());
break;
- case FORMAT_TIMESTAMP:
- sb.append(getTimestamp());
+ case FORMAT_LONG:
+ sb.append(indent).append(getLong());
break;
default:
- sb.append(SliceItem.typeToString(getFormat()));
+ sb.append(indent).append(SliceItem.typeToString(getFormat()));
break;
}
+ if (!FORMAT_SLICE.equals(getFormat())) {
+ sb.append(' ');
+ addHints(sb, mHints);
+ }
+ sb.append(",\n");
return sb.toString();
}
}
diff --git a/slices/core/src/main/java/androidx/slice/SliceProvider.java b/slices/core/src/main/java/androidx/slice/SliceProvider.java
index 7ec9232..9061ab1 100644
--- a/slices/core/src/main/java/androidx/slice/SliceProvider.java
+++ b/slices/core/src/main/java/androidx/slice/SliceProvider.java
@@ -20,20 +20,8 @@
import static android.app.slice.SliceProvider.SLICE_TYPE;
import static androidx.slice.compat.SliceProviderCompat.EXTRA_BIND_URI;
-import static androidx.slice.compat.SliceProviderCompat.EXTRA_INTENT;
import static androidx.slice.compat.SliceProviderCompat.EXTRA_PKG;
import static androidx.slice.compat.SliceProviderCompat.EXTRA_PROVIDER_PKG;
-import static androidx.slice.compat.SliceProviderCompat.EXTRA_SLICE;
-import static androidx.slice.compat.SliceProviderCompat.EXTRA_SLICE_DESCENDANTS;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_GET_DESCENDANTS;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_GET_PINNED_SPECS;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_MAP_INTENT;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_MAP_ONLY_INTENT;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_PIN;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_SLICE;
-import static androidx.slice.compat.SliceProviderCompat.METHOD_UNPIN;
-import static androidx.slice.compat.SliceProviderCompat.addSpecs;
-import static androidx.slice.compat.SliceProviderCompat.getSpecs;
import static androidx.slice.core.SliceHints.HINT_PERMISSION_REQUEST;
import android.app.PendingIntent;
@@ -48,13 +36,8 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
-import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Process;
-import android.os.StrictMode;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -63,11 +46,10 @@
import androidx.annotation.RestrictTo;
import androidx.core.app.CoreComponentFactory;
import androidx.core.os.BuildCompat;
-import androidx.slice.compat.CompatPinnedList;
+import androidx.slice.compat.SliceProviderCompat;
import androidx.slice.compat.SliceProviderWrapperContainer;
import androidx.slice.core.R;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
@@ -118,14 +100,9 @@
private static final String TAG = "SliceProvider";
- private static final String DATA_PREFIX = "slice_data_";
- private static final long SLICE_BIND_ANR = 2000;
-
private static final boolean DEBUG = false;
- private final Handler mHandler = new Handler(Looper.getMainLooper());
- private CompatPinnedList mPinnedList;
- private String mCallback;
+ private SliceProviderCompat mCompat;
/**
* Implement this to initialize your slice provider on startup.
@@ -154,8 +131,9 @@
@Override
public final boolean onCreate() {
- mPinnedList = new CompatPinnedList(getContext(),
- DATA_PREFIX + getClass().getName());
+ if (!BuildCompat.isAtLeastP()) {
+ mCompat = new SliceProviderCompat(this);
+ }
return onCreateSliceProvider();
}
@@ -167,115 +145,7 @@
@Override
public Bundle call(String method, String arg, Bundle extras) {
- if (method.equals(METHOD_SLICE)) {
- Uri uri = extras.getParcelable(EXTRA_BIND_URI);
- if (Binder.getCallingUid() != Process.myUid()) {
- getContext().enforceUriPermission(uri, Binder.getCallingPid(),
- Binder.getCallingUid(),
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
- "Slice binding requires write access to the uri");
- }
- Set<SliceSpec> specs = getSpecs(extras);
-
- Slice s = handleBindSlice(uri, specs, getCallingPackage());
- Bundle b = new Bundle();
- b.putParcelable(EXTRA_SLICE, s.toBundle());
- return b;
- } else if (method.equals(METHOD_MAP_INTENT)) {
- Intent intent = extras.getParcelable(EXTRA_INTENT);
- Uri uri = onMapIntentToUri(intent);
- Bundle b = new Bundle();
- if (uri != null) {
- Set<SliceSpec> specs = getSpecs(extras);
- Slice s = handleBindSlice(uri, specs, getCallingPackage());
- b.putParcelable(EXTRA_SLICE, s.toBundle());
- } else {
- b.putParcelable(EXTRA_SLICE, null);
- }
- return b;
- } else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
- Intent intent = extras.getParcelable(EXTRA_INTENT);
- Uri uri = onMapIntentToUri(intent);
- Bundle b = new Bundle();
- b.putParcelable(EXTRA_SLICE, uri);
- return b;
- } else if (method.equals(METHOD_PIN)) {
- Uri uri = extras.getParcelable(EXTRA_BIND_URI);
- Set<SliceSpec> specs = getSpecs(extras);
- String pkg = extras.getString(EXTRA_PKG);
- if (mPinnedList.addPin(uri, pkg, specs)) {
- handleSlicePinned(uri);
- }
- return null;
- } else if (method.equals(METHOD_UNPIN)) {
- Uri uri = extras.getParcelable(EXTRA_BIND_URI);
- String pkg = extras.getString(EXTRA_PKG);
- if (mPinnedList.removePin(uri, pkg)) {
- handleSliceUnpinned(uri);
- }
- return null;
- } else if (method.equals(METHOD_GET_PINNED_SPECS)) {
- Uri uri = extras.getParcelable(EXTRA_BIND_URI);
- Bundle b = new Bundle();
- addSpecs(b, mPinnedList.getSpecs(uri));
- return b;
- } else if (method.equals(METHOD_GET_DESCENDANTS)) {
- Uri uri = extras.getParcelable(EXTRA_BIND_URI);
- Bundle b = new Bundle();
- b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
- new ArrayList<>(handleGetDescendants(uri)));
- return b;
- }
- return super.call(method, arg, extras);
- }
-
- private Collection<Uri> handleGetDescendants(Uri uri) {
- mCallback = "onGetSliceDescendants";
- mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
- try {
- return onGetSliceDescendants(uri);
- } finally {
- mHandler.removeCallbacks(mAnr);
- }
- }
-
- private void handleSlicePinned(final Uri sliceUri) {
- mCallback = "onSlicePinned";
- mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
- try {
- onSlicePinned(sliceUri);
- } finally {
- mHandler.removeCallbacks(mAnr);
- }
- }
-
- private void handleSliceUnpinned(final Uri sliceUri) {
- mCallback = "onSliceUnpinned";
- mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
- try {
- onSliceUnpinned(sliceUri);
- } finally {
- mHandler.removeCallbacks(mAnr);
- }
- }
-
- private Slice handleBindSlice(final Uri sliceUri, final Set<SliceSpec> specs,
- final String callingPkg) {
- // This can be removed once Slice#bindSlice is removed and everyone is using
- // SliceManager#bindSlice.
- String pkg = callingPkg != null ? callingPkg
- : getContext().getPackageManager().getNameForUid(Binder.getCallingUid());
- if (Binder.getCallingUid() != Process.myUid()) {
- try {
- getContext().enforceUriPermission(sliceUri,
- Binder.getCallingPid(), Binder.getCallingUid(),
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
- "Slice binding requires write access to Uri");
- } catch (SecurityException e) {
- return createPermissionSlice(getContext(), sliceUri, pkg);
- }
- }
- return onBindSliceStrict(sliceUri, specs);
+ return mCompat != null ? mCompat.call(method, arg, extras) : null;
}
/**
@@ -337,35 +207,6 @@
}
}
- private Slice onBindSliceStrict(Uri sliceUri, Set<SliceSpec> specs) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
- mCallback = "onBindSlice";
- mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
- try {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectAll()
- .penaltyDeath()
- .build());
- SliceProvider.setSpecs(specs);
- try {
- return onBindSlice(sliceUri);
- } finally {
- SliceProvider.setSpecs(null);
- mHandler.removeCallbacks(mAnr);
- }
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
-
- private final Runnable mAnr = new Runnable() {
- @Override
- public void run() {
- Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
- Log.wtf(TAG, "Timed out while handling slice callback " + mCallback);
- }
- };
-
/**
* Implemented to create a slice.
* <p>
diff --git a/slices/core/src/main/java/androidx/slice/compat/CompatPermissionManager.java b/slices/core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
new file mode 100644
index 0000000..247a763
--- /dev/null
+++ b/slices/core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.slice.compat;
+
+import static androidx.core.content.PermissionChecker.PERMISSION_DENIED;
+import static androidx.core.content.PermissionChecker.PERMISSION_GRANTED;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.collection.ArraySet;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+class CompatPermissionManager {
+
+ private static final String TAG = "CompatPermissionManager";
+ public static final String ALL_SUFFIX = "_all";
+
+ private final Context mContext;
+ private final String mPrefsName;
+
+ CompatPermissionManager(Context context, String prefsName) {
+ mContext = context;
+ mPrefsName = prefsName;
+ }
+
+ private SharedPreferences getPrefs() {
+ return mContext.getSharedPreferences(mPrefsName, Context.MODE_PRIVATE);
+ }
+
+ public int checkSlicePermission(Uri uri, int pid, int uid) {
+ for (String pkg : mContext.getPackageManager().getPackagesForUid(uid)) {
+ if (checkSlicePermission(uri, pkg) == PERMISSION_GRANTED) {
+ return PERMISSION_GRANTED;
+ }
+ }
+ // Fall back to allowing uri permissions through.
+ return mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ private int checkSlicePermission(Uri uri, String pkg) {
+ PermissionState state = getPermissionState(pkg, uri.getAuthority());
+ return state.hasAccess(uri.getPathSegments()) ? PERMISSION_GRANTED : PERMISSION_DENIED;
+ }
+
+ public void grantSlicePermission(Uri uri, String toPkg) {
+ PermissionState state = getPermissionState(toPkg, uri.getAuthority());
+ if (state.addPath(uri.getPathSegments())) {
+ persist(state);
+ }
+ }
+
+ public void revokeSlicePermission(Uri uri, String toPkg) {
+ PermissionState state = getPermissionState(toPkg, uri.getAuthority());
+ if (state.removePath(uri.getPathSegments())) {
+ persist(state);
+ }
+ }
+
+ private synchronized void persist(PermissionState state) {
+ if (!getPrefs().edit()
+ .putStringSet(state.getKey(), state.toPersistable())
+ .putBoolean(state.getKey() + ALL_SUFFIX, state.hasAllPermissions())
+ .commit()) {
+ Log.e(TAG, "Unable to persist permissions");
+ }
+ }
+
+ private PermissionState getPermissionState(String pkg, String authority) {
+ String key = pkg + "_" + authority;
+ Set<String> grant = getPrefs().getStringSet(key, Collections.<String>emptySet());
+ boolean hasAllPermissions = getPrefs().getBoolean(key + ALL_SUFFIX, false);
+ return new PermissionState(grant, key, hasAllPermissions);
+ }
+
+ public static class PermissionState {
+
+ private final ArraySet<String[]> mPaths = new ArraySet<>();
+ private final String mKey;
+
+ PermissionState(Set<String> grant, String key, boolean hasAllPermissions) {
+ if (hasAllPermissions) {
+ mPaths.add(new String[0]);
+ } else {
+ for (String g : grant) {
+ mPaths.add(decodeSegments(g));
+ }
+ }
+ mKey = key;
+ }
+
+ public boolean hasAllPermissions() {
+ return hasAccess(Collections.<String>emptyList());
+ }
+
+ public String getKey() {
+ return mKey;
+ }
+
+ public Set<String> toPersistable() {
+ ArraySet<String> ret = new ArraySet<>();
+ for (String[] path : mPaths) {
+ ret.add(encodeSegments(path));
+ }
+ return ret;
+ }
+
+ public boolean hasAccess(List<String> path) {
+ String[] inPath = path.toArray(new String[path.size()]);
+ for (String[] p : mPaths) {
+ if (isPathPrefixMatch(p, inPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean addPath(List<String> path) {
+ String[] pathSegs = path.toArray(new String[path.size()]);
+ for (int i = mPaths.size() - 1; i >= 0; i--) {
+ String[] existing = mPaths.valueAt(i);
+ if (isPathPrefixMatch(existing, pathSegs)) {
+ // Nothing to add here.
+ return false;
+ }
+ if (isPathPrefixMatch(pathSegs, existing)) {
+ mPaths.removeAt(i);
+ }
+ }
+ mPaths.add(pathSegs);
+ return true;
+ }
+
+ boolean removePath(List<String> path) {
+ boolean changed = false;
+ String[] pathSegs = path.toArray(new String[path.size()]);
+ for (int i = mPaths.size() - 1; i >= 0; i--) {
+ String[] existing = mPaths.valueAt(i);
+ if (isPathPrefixMatch(pathSegs, existing)) {
+ changed = true;
+ mPaths.removeAt(i);
+ }
+ }
+ return changed;
+ }
+
+ private boolean isPathPrefixMatch(String[] prefix, String[] path) {
+ final int prefixSize = prefix.length;
+ if (path.length < prefixSize) return false;
+
+ for (int i = 0; i < prefixSize; i++) {
+ if (!Objects.equals(path[i], prefix[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private String encodeSegments(String[] s) {
+ String[] out = new String[s.length];
+ for (int i = 0; i < s.length; i++) {
+ out[i] = Uri.encode(s[i]);
+ }
+ return TextUtils.join("/", out);
+ }
+
+ private String[] decodeSegments(String s) {
+ String[] sets = s.split("/", -1);
+ for (int i = 0; i < sets.length; i++) {
+ sets[i] = Uri.decode(sets[i]);
+ }
+ return sets;
+ }
+ }
+}
diff --git a/slices/core/src/main/java/androidx/slice/compat/CompatPinnedList.java b/slices/core/src/main/java/androidx/slice/compat/CompatPinnedList.java
index 56b8122..da602f5 100644
--- a/slices/core/src/main/java/androidx/slice/compat/CompatPinnedList.java
+++ b/slices/core/src/main/java/androidx/slice/compat/CompatPinnedList.java
@@ -28,6 +28,8 @@
import androidx.core.util.ObjectsCompat;
import androidx.slice.SliceSpec;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
/**
@@ -70,6 +72,22 @@
return prefs;
}
+ /**
+ * Get pinned specs
+ */
+ public List<Uri> getPinnedSlices() {
+ List<Uri> pinned = new ArrayList<>();
+ for (String key : getPrefs().getAll().keySet()) {
+ if (key.startsWith(PIN_PREFIX)) {
+ Uri uri = Uri.parse(key.substring(PIN_PREFIX.length()));
+ if (!getPins(uri).isEmpty()) {
+ pinned.add(uri);
+ }
+ }
+ }
+ return pinned;
+ }
+
private Set<String> getPins(Uri uri) {
return getPrefs().getStringSet(PIN_PREFIX + uri.toString(), new ArraySet<String>());
}
@@ -85,8 +103,8 @@
if (TextUtils.isEmpty(specNamesStr) || TextUtils.isEmpty(specRevsStr)) {
return new ArraySet<>();
}
- String[] specNames = specNamesStr.split(",");
- String[] specRevs = specRevsStr.split(",");
+ String[] specNames = specNamesStr.split(",", -1);
+ String[] specRevs = specRevsStr.split(",", -1);
if (specNames.length != specRevs.length) {
return new ArraySet<>();
}
diff --git a/slices/core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java b/slices/core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
index f3270f8..5fa33ae 100644
--- a/slices/core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
+++ b/slices/core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
@@ -20,16 +20,20 @@
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
-import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
+import android.text.Html;
+import android.text.TextPaint;
+import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.RestrictTo;
import androidx.appcompat.app.AlertDialog;
+import androidx.core.text.BidiFormatter;
import androidx.slice.core.R;
/**
@@ -40,6 +44,8 @@
public class SlicePermissionActivity extends Activity implements OnClickListener,
OnDismissListener {
+ private static final float MAX_LABEL_SIZE_PX = 500f;
+
private static final String TAG = "SlicePermissionActivity";
private Uri mUri;
@@ -56,8 +62,12 @@
try {
PackageManager pm = getPackageManager();
- CharSequence app1 = pm.getApplicationInfo(mCallingPkg, 0).loadLabel(pm);
- CharSequence app2 = pm.getApplicationInfo(mProviderPkg, 0).loadLabel(pm);
+ CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(
+ loadSafeLabel(pm, pm.getApplicationInfo(mCallingPkg, 0))
+ .toString());
+ CharSequence app2 = BidiFormatter.getInstance().unicodeWrap(
+ loadSafeLabel(pm, pm.getApplicationInfo(mProviderPkg, 0))
+ .toString());
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(getString(R.string.abc_slice_permission_title, app1, app2))
.setView(R.layout.abc_slice_permission_request)
@@ -75,14 +85,50 @@
}
}
+ // Based on loadSafeLabel in PackageitemInfo
+ private CharSequence loadSafeLabel(PackageManager pm, ApplicationInfo appInfo) {
+ // loadLabel() always returns non-null
+ String label = appInfo.loadLabel(pm).toString();
+ // strip HTML tags to avoid <br> and other tags overwriting original message
+ String labelStr = Html.fromHtml(label).toString();
+
+ // If the label contains new line characters it may push the UI
+ // down to hide a part of it. Labels shouldn't have new line
+ // characters, so just truncate at the first time one is seen.
+ final int labelLength = labelStr.length();
+ int offset = 0;
+ while (offset < labelLength) {
+ final int codePoint = labelStr.codePointAt(offset);
+ final int type = Character.getType(codePoint);
+ if (type == Character.LINE_SEPARATOR
+ || type == Character.CONTROL
+ || type == Character.PARAGRAPH_SEPARATOR) {
+ labelStr = labelStr.substring(0, offset);
+ break;
+ }
+ // replace all non-break space to " " in order to be trimmed
+ if (type == Character.SPACE_SEPARATOR) {
+ labelStr = labelStr.substring(0, offset) + " " + labelStr.substring(offset
+ + Character.charCount(codePoint));
+ }
+ offset += Character.charCount(codePoint);
+ }
+
+ labelStr = labelStr.trim();
+ if (labelStr.isEmpty()) {
+ return appInfo.packageName;
+ }
+ TextPaint paint = new TextPaint();
+ paint.setTextSize(42);
+
+ return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX, TextUtils.TruncateAt.END);
+ }
+
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
- grantUriPermission(mCallingPkg, mUri.buildUpon().path("").build(),
- Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- getContentResolver().notifyChange(mUri, null);
+ SliceProviderCompat.grantSlicePermission(this, getPackageName(), mCallingPkg,
+ mUri.buildUpon().path("").build());
}
finish();
}
diff --git a/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java b/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
index 61bc65e..d62e9b5 100644
--- a/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
+++ b/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
@@ -15,19 +15,29 @@
*/
package androidx.slice.compat;
+import static android.app.slice.SliceManager.CATEGORY_SLICE;
+import static android.app.slice.SliceManager.SLICE_METADATA_KEY;
import static android.app.slice.SliceProvider.SLICE_TYPE;
+import static androidx.core.content.PermissionChecker.PERMISSION_DENIED;
+
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcelable;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -36,8 +46,8 @@
import androidx.collection.ArraySet;
import androidx.core.util.Preconditions;
import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
import androidx.slice.SliceSpec;
-import androidx.slice.core.SliceHints;
import java.util.ArrayList;
import java.util.Collection;
@@ -51,8 +61,12 @@
@RestrictTo(Scope.LIBRARY)
public class SliceProviderCompat {
private static final String TAG = "SliceProviderCompat";
+ private static final String DATA_PREFIX = "slice_data_";
+ private static final String PERMS_PREFIX = "slice_perms_";
+ private static final String ALL_FILES = DATA_PREFIX + "all_slice_files";
- public static final String EXTRA_BIND_URI = "slice_uri";
+ private static final long SLICE_BIND_ANR = 2000;
+
public static final String METHOD_SLICE = "bind_slice";
public static final String METHOD_MAP_INTENT = "map_slice";
public static final String METHOD_PIN = "pin_slice";
@@ -60,7 +74,11 @@
public static final String METHOD_GET_PINNED_SPECS = "get_specs";
public static final String METHOD_MAP_ONLY_INTENT = "map_only";
public static final String METHOD_GET_DESCENDANTS = "get_descendants";
+ public static final String METHOD_CHECK_PERMISSION = "check_perms";
+ public static final String METHOD_GRANT_PERMISSION = "grant_perms";
+ public static final String METHOD_REVOKE_PERMISSION = "revoke_perms";
+ public static final String EXTRA_BIND_URI = "slice_uri";
public static final String EXTRA_INTENT = "slice_intent";
public static final String EXTRA_SLICE = "slice";
public static final String EXTRA_SUPPORTED_SPECS = "specs";
@@ -68,6 +86,202 @@
public static final String EXTRA_PKG = "pkg";
public static final String EXTRA_PROVIDER_PKG = "provider_pkg";
public static final String EXTRA_SLICE_DESCENDANTS = "slice_descendants";
+ public static final String EXTRA_UID = "uid";
+ public static final String EXTRA_PID = "pid";
+ public static final String EXTRA_RESULT = "result";
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ private String mCallback;
+ private final SliceProvider mProvider;
+ private CompatPinnedList mPinnedList;
+ private CompatPermissionManager mPermissionManager;
+
+ public SliceProviderCompat(SliceProvider provider) {
+ mProvider = provider;
+ String prefsFile = DATA_PREFIX + getClass().getName();
+ SharedPreferences allFiles = provider.getContext().getSharedPreferences(ALL_FILES, 0);
+ Set<String> files = allFiles.getStringSet(ALL_FILES, Collections.<String>emptySet());
+ if (!files.contains(prefsFile)) {
+ // Make sure this is editable.
+ files = new ArraySet<>(files);
+ files.add(prefsFile);
+ allFiles.edit()
+ .putStringSet(ALL_FILES, files)
+ .commit();
+ }
+ mPinnedList = new CompatPinnedList(provider.getContext(), prefsFile);
+ mPermissionManager = new CompatPermissionManager(provider.getContext(),
+ PERMS_PREFIX + getClass().getName());
+ }
+
+ private Context getContext() {
+ return mProvider.getContext();
+ }
+
+ private String getCallingPackage() {
+ return mProvider.getCallingPackage();
+ }
+
+ /**
+ * Called by SliceProvider when compat is needed.
+ */
+ public Bundle call(String method, String arg, Bundle extras) {
+ if (method.equals(METHOD_SLICE)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ Set<SliceSpec> specs = getSpecs(extras);
+
+ Slice s = handleBindSlice(uri, specs, getCallingPackage());
+ Bundle b = new Bundle();
+ b.putParcelable(EXTRA_SLICE, s.toBundle());
+ return b;
+ } else if (method.equals(METHOD_MAP_INTENT)) {
+ Intent intent = extras.getParcelable(EXTRA_INTENT);
+ Uri uri = mProvider.onMapIntentToUri(intent);
+ Bundle b = new Bundle();
+ if (uri != null) {
+ Set<SliceSpec> specs = getSpecs(extras);
+ Slice s = handleBindSlice(uri, specs, getCallingPackage());
+ b.putParcelable(EXTRA_SLICE, s.toBundle());
+ } else {
+ b.putParcelable(EXTRA_SLICE, null);
+ }
+ return b;
+ } else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
+ Intent intent = extras.getParcelable(EXTRA_INTENT);
+ Uri uri = mProvider.onMapIntentToUri(intent);
+ Bundle b = new Bundle();
+ b.putParcelable(EXTRA_SLICE, uri);
+ return b;
+ } else if (method.equals(METHOD_PIN)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ Set<SliceSpec> specs = getSpecs(extras);
+ String pkg = extras.getString(EXTRA_PKG);
+ if (mPinnedList.addPin(uri, pkg, specs)) {
+ handleSlicePinned(uri);
+ }
+ return null;
+ } else if (method.equals(METHOD_UNPIN)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ String pkg = extras.getString(EXTRA_PKG);
+ if (mPinnedList.removePin(uri, pkg)) {
+ handleSliceUnpinned(uri);
+ }
+ return null;
+ } else if (method.equals(METHOD_GET_PINNED_SPECS)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ Bundle b = new Bundle();
+ addSpecs(b, mPinnedList.getSpecs(uri));
+ return b;
+ } else if (method.equals(METHOD_GET_DESCENDANTS)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ Bundle b = new Bundle();
+ b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
+ new ArrayList<>(handleGetDescendants(uri)));
+ return b;
+ } else if (method.equals(METHOD_CHECK_PERMISSION)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ String pkg = extras.getString(EXTRA_PKG);
+ int pid = extras.getInt(EXTRA_PID);
+ int uid = extras.getInt(EXTRA_UID);
+ Bundle b = new Bundle();
+ b.putInt(EXTRA_RESULT, mPermissionManager.checkSlicePermission(uri, pid, uid));
+ return b;
+ } else if (method.equals(METHOD_GRANT_PERMISSION)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ String toPkg = extras.getString(EXTRA_PKG);
+ if (Binder.getCallingUid() != Process.myUid()) {
+ throw new SecurityException("Only the owning process can manage slice permissions");
+ }
+ mPermissionManager.grantSlicePermission(uri, toPkg);
+ } else if (method.equals(METHOD_REVOKE_PERMISSION)) {
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ String toPkg = extras.getString(EXTRA_PKG);
+ if (Binder.getCallingUid() != Process.myUid()) {
+ throw new SecurityException("Only the owning process can manage slice permissions");
+ }
+ mPermissionManager.revokeSlicePermission(uri, toPkg);
+ }
+ return null;
+ }
+
+ private Collection<Uri> handleGetDescendants(Uri uri) {
+ mCallback = "onGetSliceDescendants";
+ mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
+ return mProvider.onGetSliceDescendants(uri);
+ } finally {
+ mHandler.removeCallbacks(mAnr);
+ }
+ }
+
+ private void handleSlicePinned(final Uri sliceUri) {
+ mCallback = "onSlicePinned";
+ mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
+ mProvider.onSlicePinned(sliceUri);
+ } finally {
+ mHandler.removeCallbacks(mAnr);
+ }
+ }
+
+ private void handleSliceUnpinned(final Uri sliceUri) {
+ mCallback = "onSliceUnpinned";
+ mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
+ mProvider.onSliceUnpinned(sliceUri);
+ } finally {
+ mHandler.removeCallbacks(mAnr);
+ }
+ }
+
+ private Slice handleBindSlice(final Uri sliceUri, final Set<SliceSpec> specs,
+ final String callingPkg) {
+ // This can be removed once Slice#bindSlice is removed and everyone is using
+ // SliceManager#bindSlice.
+ String pkg = callingPkg != null ? callingPkg
+ : getContext().getPackageManager().getNameForUid(Binder.getCallingUid());
+ if (Binder.getCallingUid() != Process.myUid()) {
+ try {
+ getContext().enforceUriPermission(sliceUri,
+ Binder.getCallingPid(), Binder.getCallingUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ "Slice binding requires write access to Uri");
+ } catch (SecurityException e) {
+ return mProvider.createPermissionSlice(getContext(), sliceUri, pkg);
+ }
+ }
+ return onBindSliceStrict(sliceUri, specs);
+ }
+
+ private Slice onBindSliceStrict(Uri sliceUri, Set<SliceSpec> specs) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ mCallback = "onBindSlice";
+ mHandler.postDelayed(mAnr, SLICE_BIND_ANR);
+ try {
+ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+ .detectAll()
+ .penaltyDeath()
+ .build());
+ SliceProvider.setSpecs(specs);
+ try {
+ return mProvider.onBindSlice(sliceUri);
+ } finally {
+ SliceProvider.setSpecs(null);
+ mHandler.removeCallbacks(mAnr);
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ private final Runnable mAnr = new Runnable() {
+ @Override
+ public void run() {
+ Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
+ Log.wtf(TAG, "Timed out while handling slice callback " + mCallback);
+ }
+ };
/**
* Compat version of {@link Slice#bindSlice}.
@@ -137,6 +351,10 @@
*/
public static Slice bindSlice(Context context, Intent intent,
Set<SliceSpec> supportedSpecs) {
+ Preconditions.checkNotNull(intent, "intent");
+ Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
+ || intent.getData() != null,
+ String.format("Slice intent must be explicit %s", intent));
ContentResolver resolver = context.getContentResolver();
// Check if the intent has data for the slice uri on it and use that
@@ -145,10 +363,24 @@
return bindSlice(context, intentData, supportedSpecs);
}
// Otherwise ask the app
+ Intent queryIntent = new Intent(intent);
+ if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
+ queryIntent.addCategory(CATEGORY_SLICE);
+ }
List<ResolveInfo> providers =
- context.getPackageManager().queryIntentContentProviders(intent, 0);
- if (providers == null) {
- throw new IllegalArgumentException("Unable to resolve intent " + intent);
+ context.getPackageManager().queryIntentContentProviders(queryIntent, 0);
+ if (providers == null || providers.isEmpty()) {
+ // There are no providers, see if this activity has a direct link.
+ ResolveInfo resolve = context.getPackageManager().resolveActivity(intent,
+ PackageManager.GET_META_DATA);
+ if (resolve != null && resolve.activityInfo != null
+ && resolve.activityInfo.metaData != null
+ && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
+ return bindSlice(context, Uri.parse(
+ resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY)),
+ supportedSpecs);
+ }
+ return null;
}
String authority = providers.get(0).providerInfo.authority;
Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
@@ -258,7 +490,8 @@
*/
public static Uri mapIntentToUri(Context context, Intent intent) {
Preconditions.checkNotNull(intent, "intent");
- Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null,
+ Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
+ || intent.getData() != null,
String.format("Slice intent must be explicit %s", intent));
ContentResolver resolver = context.getContentResolver();
@@ -268,17 +501,21 @@
return intentData;
}
// Otherwise ask the app
+ Intent queryIntent = new Intent(intent);
+ if (!queryIntent.hasCategory(CATEGORY_SLICE)) {
+ queryIntent.addCategory(CATEGORY_SLICE);
+ }
List<ResolveInfo> providers =
- context.getPackageManager().queryIntentContentProviders(intent, 0);
+ context.getPackageManager().queryIntentContentProviders(queryIntent, 0);
if (providers == null || providers.isEmpty()) {
// There are no providers, see if this activity has a direct link.
ResolveInfo resolve = context.getPackageManager().resolveActivity(intent,
PackageManager.GET_META_DATA);
if (resolve != null && resolve.activityInfo != null
&& resolve.activityInfo.metaData != null
- && resolve.activityInfo.metaData.containsKey(SliceHints.SLICE_METADATA_KEY)) {
+ && resolve.activityInfo.metaData.containsKey(SLICE_METADATA_KEY)) {
return Uri.parse(
- resolve.activityInfo.metaData.getString(SliceHints.SLICE_METADATA_KEY));
+ resolve.activityInfo.metaData.getString(SLICE_METADATA_KEY));
}
return null;
}
@@ -319,6 +556,73 @@
return Collections.emptyList();
}
- private SliceProviderCompat() {
+ /**
+ * Compat version of {@link android.app.slice.SliceManager#checkSlicePermission}.
+ */
+ public static int checkSlicePermission(Context context, String packageName, Uri uri, int pid,
+ int uid) {
+ ContentResolver resolver = context.getContentResolver();
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+ Bundle extras = new Bundle();
+ extras.putParcelable(EXTRA_BIND_URI, uri);
+ extras.putString(EXTRA_PKG, packageName);
+ extras.putInt(EXTRA_PID, pid);
+ extras.putInt(EXTRA_UID, uid);
+
+ final Bundle res = provider.call(METHOD_CHECK_PERMISSION, null, extras);
+ return res.getInt(EXTRA_RESULT);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to check slice permission", e);
+ }
+ return PERMISSION_DENIED;
+ }
+
+ /**
+ * Compat version of {@link android.app.slice.SliceManager#grantSlicePermission}.
+ */
+ public static void grantSlicePermission(Context context, String packageName, String toPackage,
+ Uri uri) {
+ ContentResolver resolver = context.getContentResolver();
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+ Bundle extras = new Bundle();
+ extras.putParcelable(EXTRA_BIND_URI, uri);
+ extras.putString(EXTRA_PROVIDER_PKG, packageName);
+ extras.putString(EXTRA_PKG, toPackage);
+
+ provider.call(METHOD_GRANT_PERMISSION, null, extras);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get slice descendants", e);
+ }
+ }
+
+ /**
+ * Compat version of {@link android.app.slice.SliceManager#revokeSlicePermission}.
+ */
+ public static void revokeSlicePermission(Context context, String packageName, String toPackage,
+ Uri uri) {
+ ContentResolver resolver = context.getContentResolver();
+ try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
+ Bundle extras = new Bundle();
+ extras.putParcelable(EXTRA_BIND_URI, uri);
+ extras.putString(EXTRA_PROVIDER_PKG, packageName);
+ extras.putString(EXTRA_PKG, toPackage);
+
+ provider.call(METHOD_REVOKE_PERMISSION, null, extras);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get slice descendants", e);
+ }
+ }
+
+ /**
+ * Compat version of {@link android.app.slice.SliceManager#getPinnedSlices}.
+ */
+ public static List<Uri> getPinnedSlices(Context context) {
+ ArrayList<Uri> pinnedSlices = new ArrayList<>();
+ SharedPreferences prefs = context.getSharedPreferences(ALL_FILES, 0);
+ Set<String> prefSet = prefs.getStringSet(ALL_FILES, Collections.<String>emptySet());
+ for (String pref : prefSet) {
+ pinnedSlices.addAll(new CompatPinnedList(context, pref).getPinnedSlices());
+ }
+ return pinnedSlices;
}
}
diff --git a/slices/core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java b/slices/core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java
index 8641530..c35793e 100644
--- a/slices/core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java
+++ b/slices/core/src/main/java/androidx/slice/compat/SliceProviderWrapperContainer.java
@@ -29,11 +29,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
-import androidx.collection.ArraySet;
import androidx.slice.SliceConvert;
import java.util.Collection;
-import java.util.List;
+import java.util.Set;
/**
* @hide
@@ -64,8 +63,8 @@
}
@Override
- public Slice onBindSlice(Uri sliceUri, List<SliceSpec> supportedVersions) {
- androidx.slice.SliceProvider.setSpecs(new ArraySet<>(wrap(supportedVersions)));
+ public Slice onBindSlice(Uri sliceUri, Set<SliceSpec> supportedVersions) {
+ androidx.slice.SliceProvider.setSpecs(wrap(supportedVersions));
try {
return SliceConvert.unwrap(mSliceProvider.onBindSlice(sliceUri));
} finally {
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
index 5a37826..aa95b81 100644
--- a/slices/view/api/current.txt
+++ b/slices/view/api/current.txt
@@ -5,6 +5,8 @@
method public abstract androidx.slice.Slice bindSlice(android.content.Intent);
method public abstract int checkSlicePermission(android.net.Uri, int, int);
method public static androidx.slice.SliceManager getInstance(android.content.Context);
+ method public abstract java.util.List<android.net.Uri> getPinnedSlices();
+ method public abstract java.util.Set<androidx.slice.SliceSpec> getPinnedSpecs(android.net.Uri);
method public abstract java.util.Collection<android.net.Uri> getSliceDescendants(android.net.Uri);
method public abstract void grantSlicePermission(java.lang.String, android.net.Uri);
method public abstract android.net.Uri mapIntentToUri(android.content.Intent);
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 38576c3..d214a19 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -34,9 +34,6 @@
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy)
}
-android {
-}
-
supportLibrary {
name = "Slice views"
publish = true
@@ -45,4 +42,6 @@
inceptionYear = "2017"
description = "A library that handles rendering of slice content into supported templates"
minSdkVersion = 19
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/slices/view/src/androidTest/AndroidManifest.xml b/slices/view/src/androidTest/AndroidManifest.xml
index 78f3ad8..7c90f90 100644
--- a/slices/view/src/androidTest/AndroidManifest.xml
+++ b/slices/view/src/androidTest/AndroidManifest.xml
@@ -27,6 +27,7 @@
android:exported="true">
<intent-filter>
<action android:name="androidx.slice.action.TEST" />
+ <category android:name="android.app.slice.category.SLICE" />
</intent-filter>
</provider>
diff --git a/slices/view/src/androidTest/java/androidx/slice/SliceManagerTest.java b/slices/view/src/androidTest/java/androidx/slice/SliceManagerTest.java
index 5564f72..465db2b 100644
--- a/slices/view/src/androidTest/java/androidx/slice/SliceManagerTest.java
+++ b/slices/view/src/androidTest/java/androidx/slice/SliceManagerTest.java
@@ -17,6 +17,7 @@
package androidx.slice;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -37,7 +38,6 @@
import androidx.annotation.NonNull;
import androidx.core.os.BuildCompat;
import androidx.slice.render.SliceRenderActivity;
-import androidx.slice.widget.SliceLiveData;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +45,7 @@
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.concurrent.Executor;
@RunWith(AndroidJUnit4.class)
@@ -89,6 +90,28 @@
}
@Test
+ public void testPinList() {
+ Uri uri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(mContext.getPackageName())
+ .build();
+ Uri longerUri = uri.buildUpon().appendPath("something").build();
+ try {
+ mManager.pinSlice(uri);
+ mManager.pinSlice(longerUri);
+ verify(mSliceProvider, timeout(2000)).onSlicePinned(eq(longerUri));
+
+ List<Uri> uris = mManager.getPinnedSlices();
+ assertEquals(2, uris.size());
+ assertTrue(uris.contains(uri));
+ assertTrue(uris.contains(longerUri));
+ } finally {
+ mManager.unpinSlice(uri);
+ mManager.unpinSlice(longerUri);
+ }
+ }
+
+ @Test
public void testCallback() {
if (BuildCompat.isAtLeastP()) {
return;
@@ -124,7 +147,8 @@
mManager.pinSlice(uri);
verify(mSliceProvider).onSlicePinned(eq(uri));
- assertEquals(SliceLiveData.SUPPORTED_SPECS, mManager.getPinnedSpecs(uri));
+ // Disabled while we update APIs.
+ //assertEquals(SliceLiveData.SUPPORTED_SPECS, mManager.getPinnedSpecs(uri));
}
@Test
@@ -145,8 +169,8 @@
when(mSliceProvider.onMapIntentToUri(eq(intent))).thenReturn(expected);
Uri uri = mManager.mapIntentToUri(intent);
- assertEquals(expected, uri);
verify(mSliceProvider).onMapIntentToUri(eq(intent));
+ assertEquals(expected, uri);
}
@Test
diff --git a/slices/view/src/androidTest/java/androidx/slice/SlicePermissionTest.java b/slices/view/src/androidTest/java/androidx/slice/SlicePermissionTest.java
new file mode 100644
index 0000000..ffb65e0
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/slice/SlicePermissionTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.slice;
+
+import static androidx.core.content.PermissionChecker.PERMISSION_DENIED;
+import static androidx.core.content.PermissionChecker.PERMISSION_GRANTED;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.os.Process;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SlicePermissionTest {
+
+ private static final Uri BASE_URI = Uri.parse("content://androidx.slice.view.test/");
+ private final Context mContext = InstrumentationRegistry.getContext();
+ private String mTestPkg;
+ private int mTestUid;
+ private int mTestPid;
+ private SliceManager mSliceManager;
+
+ @Before
+ public void setup() throws NameNotFoundException {
+ mSliceManager = SliceManager.getInstance(mContext);
+ mTestPkg = mContext.getPackageName();
+ mTestUid = mContext.getPackageManager().getPackageUid(mTestPkg, 0);
+ mTestPid = Process.myPid();
+ }
+
+ @After
+ public void tearDown() {
+ mSliceManager.revokeSlicePermission(mTestPkg, BASE_URI);
+ }
+
+ @Test
+ public void testGrant() {
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, BASE_URI);
+
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+ }
+
+ @Test
+ public void testGrantParent() {
+ Uri uri = BASE_URI.buildUpon()
+ .appendPath("something")
+ .build();
+
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, BASE_URI);
+
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+ }
+
+ @Test
+ public void testGrantParentExpands() {
+ Uri uri = BASE_URI.buildUpon()
+ .appendPath("something")
+ .build();
+
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, uri);
+
+ // Only sub-path granted.
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, BASE_URI);
+
+ // Now all granted.
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+ }
+
+ @Test
+ public void testGrantChild() {
+ Uri uri = BASE_URI.buildUpon()
+ .appendPath("something")
+ .build();
+
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, uri);
+
+ // Still no permission because only a child was granted
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+ }
+
+ @Test
+ public void testRevoke() {
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, BASE_URI);
+
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.revokeSlicePermission(mTestPkg, BASE_URI);
+
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+ }
+
+ @Test
+ public void testRevokeParent() {
+ Uri uri = BASE_URI.buildUpon()
+ .appendPath("something")
+ .build();
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, uri);
+
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+
+ mSliceManager.revokeSlicePermission(mTestPkg, BASE_URI);
+
+ // Revoked because parent was revoked
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(uri, mTestPid, mTestUid));
+ }
+
+ @Test
+ public void testRevokeChild() {
+ Uri uri = BASE_URI.buildUpon()
+ .appendPath("something")
+ .build();
+ assertEquals(PERMISSION_DENIED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.grantSlicePermission(mTestPkg, BASE_URI);
+
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+
+ mSliceManager.revokeSlicePermission(mTestPkg, uri);
+
+ // Not revoked because child was revoked.
+ assertEquals(PERMISSION_GRANTED,
+ mSliceManager.checkSlicePermission(BASE_URI, mTestPid, mTestUid));
+ }
+
+}
diff --git a/slices/view/src/main/java/androidx/slice/SliceManager.java b/slices/view/src/main/java/androidx/slice/SliceManager.java
index 63c56e8..83febcc 100644
--- a/slices/view/src/main/java/androidx/slice/SliceManager.java
+++ b/slices/view/src/main/java/androidx/slice/SliceManager.java
@@ -28,6 +28,7 @@
import androidx.core.os.BuildCompat;
import java.util.Collection;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -125,10 +126,8 @@
* <p>
* This is the set of specs supported for a specific pinned slice. It will take
* into account all clients and returns only specs supported by all.
- * @hide
* @see SliceSpec
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public abstract @NonNull Set<SliceSpec> getPinnedSpecs(@NonNull Uri uri);
/**
@@ -141,9 +140,8 @@
public abstract @Nullable Slice bindSlice(@NonNull Uri uri);
/**
- * Turns a slice intent into slice content. Expects an explicit intent. If there is no
- * {@link android.content.ContentProvider} associated with the given intent this will throw
- * {@link IllegalArgumentException}.
+ * Turns a slice intent into slice content. Is a shortcut to perform the action
+ * of both {@link #mapIntentToUri(Intent)} and {@link #bindSlice(Uri)} at once.
*
* @param intent The intent associated with a slice.
* @return The Slice provided by the app or null if none is given.
@@ -154,12 +152,23 @@
public abstract @Nullable Slice bindSlice(@NonNull Intent intent);
/**
- * Turns a slice intent into a slice uri. Expects an explicit intent. If there is no
- * {@link android.content.ContentProvider} associated with the given intent this will throw
- * {@link IllegalArgumentException}.
- *
+ * Turns a slice intent into a slice uri. Expects an explicit intent.
+ * <p>
+ * This goes through a several stage resolution process to determine if any slice
+ * can represent this intent.
+ * <ol>
+ * <li> If the intent contains data that {@link android.content.ContentResolver#getType} is
+ * {@link android.app.slice.SliceProvider#SLICE_TYPE} then the data will be returned.</li>
+ * <li>If the intent explicitly points at an activity, and that activity has
+ * meta-data for key {@link android.app.slice.SliceManager#SLICE_METADATA_KEY},
+ * then the Uri specified there will be returned.</li>
+ * <li>Lastly, if the intent with {@link android.app.slice.SliceManager#CATEGORY_SLICE} added
+ * resolves to a provider, then the provider will be asked to
+ * {@link SliceProvider#onMapIntentToUri} and that result will be returned.</li>
+ * <li>If no slice is found, then {@code null} is returned.</li>
+ * </ol>
* @param intent The intent associated with a slice.
- * @return The Slice Uri provided by the app or null if none is given.
+ * @return The Slice Uri provided by the app or null if none exists.
* @see Slice
* @see SliceProvider#onMapIntentToUri(Intent)
* @see Intent
@@ -223,6 +232,12 @@
public abstract @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri);
/**
+ * Get the list of currently pinned slices for this app.
+ * @see SliceProvider#onSlicePinned
+ */
+ public abstract @NonNull List<Uri> getPinnedSlices();
+
+ /**
* Class that listens to changes in {@link Slice}s.
*/
public interface SliceCallback {
diff --git a/slices/view/src/main/java/androidx/slice/SliceManagerBase.java b/slices/view/src/main/java/androidx/slice/SliceManagerBase.java
index fb9fccd..5192dad 100644
--- a/slices/view/src/main/java/androidx/slice/SliceManagerBase.java
+++ b/slices/view/src/main/java/androidx/slice/SliceManagerBase.java
@@ -19,11 +19,9 @@
import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
import android.content.Context;
-import android.content.Intent;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
@@ -31,7 +29,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
-import androidx.core.content.PermissionChecker;
import java.util.concurrent.Executor;
@@ -71,31 +68,6 @@
if (impl != null) impl.stopListening();
}
- @Override
- @PermissionChecker.PermissionResult
- public int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
- // TODO: Switch off Uri permissions.
- return mContext.checkUriPermission(uri, pid, uid,
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- }
-
- @Override
- public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
- // TODO: Switch off Uri permissions.
- mContext.grantUriPermission(toPackage, uri,
- Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- }
-
- @Override
- public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
- // TODO: Switch off Uri permissions.
- if (Build.VERSION.SDK_INT >= 26) {
- mContext.revokeUriPermission(toPackage, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- }
- }
-
private SliceListenerImpl getListener(Uri uri, SliceCallback callback,
SliceListenerImpl listener) {
diff --git a/slices/view/src/main/java/androidx/slice/SliceManagerCompat.java b/slices/view/src/main/java/androidx/slice/SliceManagerCompat.java
index 1badbb4..0018c13 100644
--- a/slices/view/src/main/java/androidx/slice/SliceManagerCompat.java
+++ b/slices/view/src/main/java/androidx/slice/SliceManagerCompat.java
@@ -29,6 +29,7 @@
import androidx.slice.widget.SliceLiveData;
import java.util.Collection;
+import java.util.List;
import java.util.Set;
@@ -76,7 +77,30 @@
}
@Override
+ public int checkSlicePermission(Uri uri, int pid, int uid) {
+ return SliceProviderCompat.checkSlicePermission(mContext, mContext.getPackageName(), uri,
+ pid, uid);
+ }
+
+ @Override
+ public void grantSlicePermission(String toPackage, Uri uri) {
+ SliceProviderCompat.grantSlicePermission(mContext, mContext.getPackageName(), toPackage,
+ uri);
+ }
+
+ @Override
+ public void revokeSlicePermission(String toPackage, Uri uri) {
+ SliceProviderCompat.revokeSlicePermission(mContext, mContext.getPackageName(), toPackage,
+ uri);
+ }
+
+ @Override
public Collection<Uri> getSliceDescendants(Uri uri) {
return SliceProviderCompat.getSliceDescendants(mContext, uri);
}
+
+ @Override
+ public List<Uri> getPinnedSlices() {
+ return SliceProviderCompat.getPinnedSlices(mContext);
+ }
}
diff --git a/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java b/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java
index e0c0342..ec49fe2 100644
--- a/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java
+++ b/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java
@@ -28,9 +28,10 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
+import androidx.core.content.PermissionChecker;
-import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -42,7 +43,7 @@
class SliceManagerWrapper extends SliceManagerBase {
private final android.app.slice.SliceManager mManager;
- private final List<SliceSpec> mSpecs;
+ private final Set<SliceSpec> mSpecs;
SliceManagerWrapper(Context context) {
this(context, context.getSystemService(android.app.slice.SliceManager.class));
@@ -51,7 +52,7 @@
SliceManagerWrapper(Context context, android.app.slice.SliceManager manager) {
super(context);
mManager = manager;
- mSpecs = new ArrayList<>(unwrap(SUPPORTED_SPECS));
+ mSpecs = unwrap(SUPPORTED_SPECS);
}
@Override
@@ -66,7 +67,9 @@
@Override
public @NonNull Set<androidx.slice.SliceSpec> getPinnedSpecs(@NonNull Uri uri) {
- return SliceConvert.wrap(mManager.getPinnedSpecs(uri));
+ // Disabled while we update APIs.
+ //return SliceConvert.wrap(mManager.getPinnedSpecs(uri));
+ return Collections.EMPTY_SET;
}
@Nullable
@@ -86,9 +89,30 @@
return mManager.getSliceDescendants(uri);
}
+ @Override
+ @PermissionChecker.PermissionResult
+ public int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
+ return mManager.checkSlicePermission(uri, pid, uid);
+ }
+
+ @Override
+ public void grantSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
+ mManager.grantSlicePermission(toPackage, uri);
+ }
+
+ @Override
+ public void revokeSlicePermission(@NonNull String toPackage, @NonNull Uri uri) {
+ mManager.revokeSlicePermission(toPackage, uri);
+ }
+
@Nullable
@Override
public Uri mapIntentToUri(@NonNull Intent intent) {
return mManager.mapIntentToUri(intent);
}
+
+ @Override
+ public List<Uri> getPinnedSlices() {
+ return mManager.getPinnedSlices();
+ }
}
diff --git a/slices/view/src/main/java/androidx/slice/SliceMetadata.java b/slices/view/src/main/java/androidx/slice/SliceMetadata.java
index 8a4ee03..0c4f614 100644
--- a/slices/view/src/main/java/androidx/slice/SliceMetadata.java
+++ b/slices/view/src/main/java/androidx/slice/SliceMetadata.java
@@ -23,9 +23,9 @@
import static android.app.slice.Slice.SUBTYPE_MAX;
import static android.app.slice.Slice.SUBTYPE_VALUE;
import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static androidx.slice.core.SliceHints.HINT_KEYWORDS;
import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
@@ -118,11 +118,11 @@
private SliceMetadata(@NonNull Context context, @NonNull Slice slice) {
mSlice = slice;
mContext = context;
- SliceItem ttlItem = SliceQuery.find(slice, FORMAT_TIMESTAMP, HINT_TTL, null);
+ SliceItem ttlItem = SliceQuery.find(slice, FORMAT_LONG, HINT_TTL, null);
if (ttlItem != null) {
mExpiry = ttlItem.getTimestamp();
}
- SliceItem updatedItem = SliceQuery.find(slice, FORMAT_TIMESTAMP, HINT_LAST_UPDATED, null);
+ SliceItem updatedItem = SliceQuery.find(slice, FORMAT_LONG, HINT_LAST_UPDATED, null);
if (updatedItem != null) {
mLastUpdated = updatedItem.getTimestamp();
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/GridContent.java b/slices/view/src/main/java/androidx/slice/widget/GridContent.java
index 69d5c44..424143c 100644
--- a/slices/view/src/main/java/androidx/slice/widget/GridContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/GridContent.java
@@ -26,9 +26,9 @@
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static androidx.slice.core.SliceHints.HINT_KEYWORDS;
import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
@@ -295,7 +295,7 @@
if (SUBTYPE_CONTENT_DESCRIPTION.equals(item.getSubType())) {
mContentDescr = item;
} else if (mTextCount < 2 && (FORMAT_TEXT.equals(itemFormat)
- || FORMAT_TIMESTAMP.equals(itemFormat))) {
+ || FORMAT_LONG.equals(itemFormat))) {
mTextCount++;
mCellItems.add(item);
} else if (imageCount < 1 && FORMAT_IMAGE.equals(item.getFormat())) {
@@ -340,7 +340,7 @@
|| cellItem.hasAnyHints(HINT_KEYWORDS, HINT_TTL, HINT_LAST_UPDATED);
return !isNonCellContent
&& (FORMAT_TEXT.equals(format)
- || FORMAT_TIMESTAMP.equals(format)
+ || FORMAT_LONG.equals(format)
|| FORMAT_IMAGE.equals(format));
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/GridRowView.java b/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
index 4b8078c..7423b02 100644
--- a/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
@@ -21,9 +21,9 @@
import static android.app.slice.Slice.HINT_TITLE;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -258,7 +258,7 @@
SliceItem item = cellItems.get(i);
final String itemFormat = item.getFormat();
if (textCount < maxCellText && (FORMAT_TEXT.equals(itemFormat)
- || FORMAT_TIMESTAMP.equals(itemFormat))) {
+ || FORMAT_LONG.equals(itemFormat))) {
if (textItems != null && !textItems.contains(item)) {
continue;
}
@@ -305,13 +305,13 @@
private boolean addItem(SliceItem item, int color, ViewGroup container, boolean singleItem) {
final String format = item.getFormat();
View addedView = null;
- if (FORMAT_TEXT.equals(format) || FORMAT_TIMESTAMP.equals(format)) {
+ if (FORMAT_TEXT.equals(format) || FORMAT_LONG.equals(format)) {
boolean title = SliceQuery.hasAnyHints(item, HINT_LARGE, HINT_TITLE);
TextView tv = (TextView) LayoutInflater.from(getContext()).inflate(title
? TITLE_TEXT_LAYOUT : TEXT_LAYOUT, null);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, title ? mTitleSize : mSubtitleSize);
tv.setTextColor(title ? mTitleColor : mSubtitleColor);
- CharSequence text = FORMAT_TIMESTAMP.equals(format)
+ CharSequence text = FORMAT_LONG.equals(format)
? SliceViewUtil.getRelativeTimeString(item.getTimestamp())
: item.getText();
tv.setText(text);
diff --git a/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java b/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java
index e09405c..9578e21 100644
--- a/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java
+++ b/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java
@@ -191,8 +191,6 @@
null);
break;
}
- int mode = mParent != null ? mParent.getMode() : MODE_LARGE;
- ((SliceChildView) v).setMode(mode);
return v;
}
@@ -248,6 +246,8 @@
mSliceChildView.setOnTouchListener(this);
final boolean isHeader = position == HEADER_INDEX;
+ int mode = mParent != null ? mParent.getMode() : MODE_LARGE;
+ mSliceChildView.setMode(mode);
mSliceChildView.setTint(mColor);
mSliceChildView.setStyle(mAttrs, mDefStyleAttr, mDefStyleRes);
mSliceChildView.setSliceItem(item, isHeader, position, mSliceObserver);
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/slice/widget/RowContent.java
index bc3826f..0c8d4a6 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowContent.java
@@ -27,10 +27,10 @@
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static androidx.slice.core.SliceHints.HINT_KEYWORDS;
import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
@@ -157,11 +157,11 @@
}
// Special rules for end items: only one timestamp
boolean hasTimestamp = mStartItem != null
- && FORMAT_TIMESTAMP.equals(mStartItem.getFormat());
+ && FORMAT_LONG.equals(mStartItem.getFormat());
for (int i = 0; i < endItems.size(); i++) {
final SliceItem item = endItems.get(i);
boolean isAction = SliceQuery.find(item, FORMAT_ACTION) != null;
- if (FORMAT_TIMESTAMP.equals(item.getFormat())) {
+ if (FORMAT_LONG.equals(item.getFormat())) {
if (!hasTimestamp) {
hasTimestamp = true;
mEndItems.add(item);
@@ -382,7 +382,7 @@
return (FORMAT_TEXT.equals(itemFormat)
&& !SUBTYPE_CONTENT_DESCRIPTION.equals(item.getSubType()))
|| FORMAT_IMAGE.equals(itemFormat)
- || FORMAT_TIMESTAMP.equals(itemFormat)
+ || FORMAT_LONG.equals(itemFormat)
|| FORMAT_REMOTE_INPUT.equals(itemFormat)
|| (FORMAT_SLICE.equals(itemFormat) && item.hasHint(HINT_TITLE)
&& !item.hasHint(HINT_SHORTCUT))
@@ -400,7 +400,7 @@
final String type = item.getFormat();
return (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null))
|| FORMAT_IMAGE.equals(type)
- || (FORMAT_TIMESTAMP.equals(type)
+ || (FORMAT_LONG.equals(type)
&& !item.hasAnyHints(HINT_TTL, HINT_LAST_UPDATED));
}
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index a7101fe..2840db9 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -26,8 +26,8 @@
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_LONG;
import static android.app.slice.SliceItem.FORMAT_SLICE;
-import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
import static androidx.slice.core.SliceHints.ICON_IMAGE;
import static androidx.slice.core.SliceHints.SMALL_IMAGE;
@@ -278,7 +278,7 @@
// If we're here we can can show end items; check for top level actions first
List<SliceItem> endItems = mRowContent.getEndItems();
- if (mIsHeader && mHeaderActions != null && mHeaderActions.size() > 0) {
+ if (mHeaderActions != null && mHeaderActions.size() > 0) {
// Use these if we have them instead
endItems = mHeaderActions;
}
@@ -460,7 +460,7 @@
if (FORMAT_IMAGE.equals(sliceItem.getFormat())) {
icon = sliceItem.getIcon();
imageMode = sliceItem.hasHint(HINT_NO_TINT) ? SMALL_IMAGE : ICON_IMAGE;
- } else if (FORMAT_TIMESTAMP.equals(sliceItem.getFormat())) {
+ } else if (FORMAT_LONG.equals(sliceItem.getFormat())) {
timeStamp = sliceItem;
}
View addedView = null;
diff --git a/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java b/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java
index 37ef17b..3afda5d 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ShortcutView.java
@@ -195,7 +195,7 @@
if (mActionItem == null) {
mActionItem = new SliceItem(PendingIntent.getActivity(context, 0,
pm.getLaunchIntentForPackage(appInfo.packageName), 0),
- new Slice.Builder(slice.getUri()).build(), FORMAT_SLICE,
+ new Slice.Builder(slice.getUri()).build(), FORMAT_ACTION,
null /* subtype */, null);
}
}
diff --git a/slices/view/src/main/res/values-as/strings.xml b/slices/view/src/main/res/values-as/strings.xml
index dbc598f..77f9af6 100644
--- a/slices/view/src/main/res/values-as/strings.xml
+++ b/slices/view/src/main/res/values-as/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"অধিক"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"অধিক দেখুৱাওক"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> আপডেট কৰা হৈছিল"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> মিনিট আগেয়ে</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> মিনিট আগেয়ে</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> বছৰ আগেয়ে</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> বছৰ আগেয়ে</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> দিন আগেয়ে</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g>দিন আগেয়ে</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"সংযোগ কৰিব পৰা নগ\'ল"</string>
</resources>
diff --git a/slices/view/src/main/res/values-be/strings.xml b/slices/view/src/main/res/values-be/strings.xml
index b03f283..f1ae045 100644
--- a/slices/view/src/main/res/values-be/strings.xml
+++ b/slices/view/src/main/res/values-be/strings.xml
@@ -21,23 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Яшчэ"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Яшчэ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Абноўлена <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> хвіліну таму</item>
- <item quantity="few"><xliff:g id="ID_2">%d</xliff:g> хвіліны таму</item>
- <item quantity="many"><xliff:g id="ID_2">%d</xliff:g> хвілін таму</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> хвіліны таму</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> год таму</item>
- <item quantity="few"><xliff:g id="ID_2">%d</xliff:g> гады таму</item>
- <item quantity="many"><xliff:g id="ID_2">%d</xliff:g> гадоў таму</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> года таму</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> дзень таму</item>
- <item quantity="few"><xliff:g id="ID_2">%d</xliff:g> дні таму</item>
- <item quantity="many"><xliff:g id="ID_2">%d</xliff:g> дзён таму</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> дня таму</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Не атрымалася падключыцца"</string>
</resources>
diff --git a/slices/view/src/main/res/values-bn/strings.xml b/slices/view/src/main/res/values-bn/strings.xml
index bc5c45b..3b8acdf 100644
--- a/slices/view/src/main/res/values-bn/strings.xml
+++ b/slices/view/src/main/res/values-bn/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"আরও"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"আরও দেখুন"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> আপডেট করা হয়েছে"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> মিনিট আগে</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> মিনিট আগে</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> বছর আগে</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> বছর আগে</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> দিন আগে</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> দিন আগে</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"কানেক্ট করা যায়নি"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ca/strings.xml b/slices/view/src/main/res/values-ca/strings.xml
index cc5dde0..52e1988 100644
--- a/slices/view/src/main/res/values-ca/strings.xml
+++ b/slices/view/src/main/res/values-ca/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Més"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Mostra\'n més"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"S\'ha actualitzat <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">Fa <xliff:g id="ID_2">%d</xliff:g> min</item>
- <item quantity="one">Fa <xliff:g id="ID_1">%d</xliff:g> min</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">Fa <xliff:g id="ID_2">%d</xliff:g> anys</item>
- <item quantity="one">Fa <xliff:g id="ID_1">%d</xliff:g> any</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">Fa <xliff:g id="ID_2">%d</xliff:g> dies</item>
- <item quantity="one">Fa <xliff:g id="ID_1">%d</xliff:g> dia</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"No s\'ha pogut connectar"</string>
</resources>
diff --git a/slices/view/src/main/res/values-da/strings.xml b/slices/view/src/main/res/values-da/strings.xml
index c7c2850..33d9c9d 100644
--- a/slices/view/src/main/res/values-da/strings.xml
+++ b/slices/view/src/main/res/values-da/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Mere"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Se mere"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Opdateret <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one">for <xliff:g id="ID_2">%d</xliff:g> min. siden</item>
- <item quantity="other">for <xliff:g id="ID_2">%d</xliff:g> min. siden</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one">for <xliff:g id="ID_2">%d</xliff:g> år siden</item>
- <item quantity="other">for <xliff:g id="ID_2">%d</xliff:g> år siden</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one">for <xliff:g id="ID_2">%d</xliff:g> dag siden</item>
- <item quantity="other">for <xliff:g id="ID_2">%d</xliff:g> dage siden</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Der kunne ikke oprettes forbindelse"</string>
</resources>
diff --git a/slices/view/src/main/res/values-de/strings.xml b/slices/view/src/main/res/values-de/strings.xml
index 25dff37..96da7eb 100644
--- a/slices/view/src/main/res/values-de/strings.xml
+++ b/slices/view/src/main/res/values-de/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Mehr"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Mehr anzeigen"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Aktualisiert: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">vor <xliff:g id="ID_2">%d</xliff:g> Min.</item>
- <item quantity="one">vor <xliff:g id="ID_1">%d</xliff:g> Min.</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">vor <xliff:g id="ID_2">%d</xliff:g> Jahren</item>
- <item quantity="one">vor <xliff:g id="ID_1">%d</xliff:g> Jahr</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">vor <xliff:g id="ID_2">%d</xliff:g> Tagen</item>
- <item quantity="one">vor <xliff:g id="ID_1">%d</xliff:g> Tag</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Verbindung nicht möglich"</string>
</resources>
diff --git a/slices/view/src/main/res/values-es-rUS/strings.xml b/slices/view/src/main/res/values-es-rUS/strings.xml
index 3125104..124c40c 100644
--- a/slices/view/src/main/res/values-es-rUS/strings.xml
+++ b/slices/view/src/main/res/values-es-rUS/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Más"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar más"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Última actualización: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">Hace <xliff:g id="ID_2">%d</xliff:g> min</item>
- <item quantity="one">Hace <xliff:g id="ID_1">%d</xliff:g> min</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">Hace <xliff:g id="ID_2">%d</xliff:g> años</item>
- <item quantity="one">Hace <xliff:g id="ID_1">%d</xliff:g> año</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">Hace <xliff:g id="ID_2">%d</xliff:g> días</item>
- <item quantity="one">Hace <xliff:g id="ID_1">%d</xliff:g> día</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"No se pudo establecer conexión"</string>
</resources>
diff --git a/slices/view/src/main/res/values-es/strings.xml b/slices/view/src/main/res/values-es/strings.xml
index f6e42fc..57685ba 100644
--- a/slices/view/src/main/res/values-es/strings.xml
+++ b/slices/view/src/main/res/values-es/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Más"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Ver más"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Última actualización: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">hace <xliff:g id="ID_2">%d</xliff:g> minutos</item>
- <item quantity="one">hace <xliff:g id="ID_1">%d</xliff:g> minuto</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">hace <xliff:g id="ID_2">%d</xliff:g> años</item>
- <item quantity="one">hace <xliff:g id="ID_1">%d</xliff:g> año</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">hace <xliff:g id="ID_2">%d</xliff:g> días</item>
- <item quantity="one">hace <xliff:g id="ID_1">%d</xliff:g> día</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"No se ha podido establecer la conexión"</string>
</resources>
diff --git a/slices/view/src/main/res/values-et/strings.xml b/slices/view/src/main/res/values-et/strings.xml
index 7e053e9..4bd8a92 100644
--- a/slices/view/src/main/res/values-et/strings.xml
+++ b/slices/view/src/main/res/values-et/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Rohkem"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Kuva rohkem"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Värskendatud kell <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min tagasi</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> min tagasi</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> a tagasi</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> a tagasi</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> päeva tagasi</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> päev tagasi</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Ühendamine ebaõnnestus"</string>
</resources>
diff --git a/slices/view/src/main/res/values-eu/strings.xml b/slices/view/src/main/res/values-eu/strings.xml
index 5e0642c..e689ada 100644
--- a/slices/view/src/main/res/values-eu/strings.xml
+++ b/slices/view/src/main/res/values-eu/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Gehiago"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Erakutsi gehiago"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Azken eguneratzea: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">Duela <xliff:g id="ID_2">%d</xliff:g> minutu</item>
- <item quantity="one">Duela <xliff:g id="ID_1">%d</xliff:g> minutu</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">Duela <xliff:g id="ID_2">%d</xliff:g> urte</item>
- <item quantity="one">Duela <xliff:g id="ID_1">%d</xliff:g> urte</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">Duela <xliff:g id="ID_2">%d</xliff:g> egun</item>
- <item quantity="one">Duela <xliff:g id="ID_1">%d</xliff:g> egun</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Ezin izan da konektatu"</string>
</resources>
diff --git a/slices/view/src/main/res/values-fa/strings.xml b/slices/view/src/main/res/values-fa/strings.xml
index 7832e8a..cb94e5d 100644
--- a/slices/view/src/main/res/values-fa/strings.xml
+++ b/slices/view/src/main/res/values-fa/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="abc_slice_more" msgid="1983560225998630901">"بیشتر"</string>
- <string name="abc_slice_show_more" msgid="1567717014004692768">"بیشتر ببینید"</string>
+ <string name="abc_slice_show_more" msgid="1567717014004692768">"نمایش موارد بیشتر"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"زمان بهروزرسانی <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
<item quantity="one"><xliff:g id="ID_2">%d</xliff:g> دقیقه قبل</item>
diff --git a/slices/view/src/main/res/values-fi/strings.xml b/slices/view/src/main/res/values-fi/strings.xml
index dbbe0cd..bc37611 100644
--- a/slices/view/src/main/res/values-fi/strings.xml
+++ b/slices/view/src/main/res/values-fi/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Lisää"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Näytä lisää"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Päivitetty <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min sitten</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> min sitten</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> vuotta sitten</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> vuosi sitten</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> päivää sitten</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> päivä sitten</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Ei yhteyttä"</string>
</resources>
diff --git a/slices/view/src/main/res/values-fr-rCA/strings.xml b/slices/view/src/main/res/values-fr-rCA/strings.xml
index 63c7fcd..1563136 100644
--- a/slices/view/src/main/res/values-fr-rCA/strings.xml
+++ b/slices/view/src/main/res/values-fr-rCA/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Plus"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Plus"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Mise à jour : <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one">Il y a <xliff:g id="ID_2">%d</xliff:g> minute</item>
- <item quantity="other">Il y a <xliff:g id="ID_2">%d</xliff:g> minutes</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one">Il y a <xliff:g id="ID_2">%d</xliff:g> an</item>
- <item quantity="other">Il y a <xliff:g id="ID_2">%d</xliff:g> ans</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one">Il y a <xliff:g id="ID_2">%d</xliff:g> jour</item>
- <item quantity="other">Il y a <xliff:g id="ID_2">%d</xliff:g> jours</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Impossible de se connecter"</string>
</resources>
diff --git a/slices/view/src/main/res/values-fr/strings.xml b/slices/view/src/main/res/values-fr/strings.xml
index 47ff242..6762544 100644
--- a/slices/view/src/main/res/values-fr/strings.xml
+++ b/slices/view/src/main/res/values-fr/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Plus"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Afficher plus"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Dernière mise à jour : <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one">Il y a <xliff:g id="ID_2">%d</xliff:g> minute</item>
- <item quantity="other">Il y a <xliff:g id="ID_2">%d</xliff:g> minutes</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one">Il y a <xliff:g id="ID_2">%d</xliff:g> an</item>
- <item quantity="other">Il y a <xliff:g id="ID_2">%d</xliff:g> ans</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one">Il y a <xliff:g id="ID_2">%d</xliff:g> jour</item>
- <item quantity="other">Il y a <xliff:g id="ID_2">%d</xliff:g> jours</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Impossible de se connecter"</string>
</resources>
diff --git a/slices/view/src/main/res/values-gl/strings.xml b/slices/view/src/main/res/values-gl/strings.xml
index fb3d1c2..70b31bb 100644
--- a/slices/view/src/main/res/values-gl/strings.xml
+++ b/slices/view/src/main/res/values-gl/strings.xml
@@ -22,16 +22,16 @@
<string name="abc_slice_show_more" msgid="1567717014004692768">"Amosar máis"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Contido actualizado (<xliff:g id="TIME">%1$s</xliff:g>)"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">hai <xliff:g id="ID_2">%d</xliff:g> min</item>
- <item quantity="one">hai <xliff:g id="ID_1">%d</xliff:g> min</item>
+ <item quantity="other">Hai <xliff:g id="ID_2">%d</xliff:g> min</item>
+ <item quantity="one">Hai <xliff:g id="ID_1">%d</xliff:g> min</item>
</plurals>
<plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">hai <xliff:g id="ID_2">%d</xliff:g> anos</item>
- <item quantity="one">hai <xliff:g id="ID_1">%d</xliff:g> ano</item>
+ <item quantity="other">Hai <xliff:g id="ID_2">%d</xliff:g> anos</item>
+ <item quantity="one">Hai <xliff:g id="ID_1">%d</xliff:g> ano</item>
</plurals>
<plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">hai <xliff:g id="ID_2">%d</xliff:g> días</item>
- <item quantity="one">hai <xliff:g id="ID_1">%d</xliff:g> día</item>
+ <item quantity="other">Hai <xliff:g id="ID_2">%d</xliff:g> días</item>
+ <item quantity="one">Hai <xliff:g id="ID_1">%d</xliff:g> día</item>
</plurals>
<string name="abc_slice_error" msgid="4188371422904147368">"Non se puido establecer conexión"</string>
</resources>
diff --git a/slices/view/src/main/res/values-gu/strings.xml b/slices/view/src/main/res/values-gu/strings.xml
index 4951f8c..d6a7ee8 100644
--- a/slices/view/src/main/res/values-gu/strings.xml
+++ b/slices/view/src/main/res/values-gu/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"વધુ"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"વધુ બતાવો"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> અપડેટ થયું"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> મિનિટ પહેલાં</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> મિનિટ પહેલાં</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> વર્ષ પહેલાં</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> વર્ષ પહેલાં</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> દિવસ પહેલાં</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> દિવસ પહેલાં</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"કનેક્ટ કરી શકાયું નથી"</string>
</resources>
diff --git a/slices/view/src/main/res/values-hi/strings.xml b/slices/view/src/main/res/values-hi/strings.xml
index 79a64bb..380025e 100644
--- a/slices/view/src/main/res/values-hi/strings.xml
+++ b/slices/view/src/main/res/values-hi/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"ज़्यादा देखें"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"ज़्यादा देखें"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> बजे अपडेट किया गया"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> मिनट पहले</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> मिनट पहले</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> साल पहले</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> साल पहले</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> दिन पहले</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> दिन पहले</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"कनेक्ट नहीं हो पाया"</string>
</resources>
diff --git a/slices/view/src/main/res/values-hu/strings.xml b/slices/view/src/main/res/values-hu/strings.xml
index cf5ebdc..c56143b 100644
--- a/slices/view/src/main/res/values-hu/strings.xml
+++ b/slices/view/src/main/res/values-hu/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Több"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Több megjelenítése"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Frissítve: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> perce</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> perce</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> éve</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> éve</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> napja</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> napja</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Nem sikerült kapcsolódni"</string>
</resources>
diff --git a/slices/view/src/main/res/values-hy/strings.xml b/slices/view/src/main/res/values-hy/strings.xml
index fcf96af..bb6b812 100644
--- a/slices/view/src/main/res/values-hy/strings.xml
+++ b/slices/view/src/main/res/values-hy/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Ավելին"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Ցուցադրել ավելի շատ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Թարմացվել է <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> րոպե առաջ</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> րոպե առաջ</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> տարի առաջ</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> տարի առաջ</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> օր առաջ</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> օր առաջ</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Չհաջողվեց միանալ"</string>
</resources>
diff --git a/slices/view/src/main/res/values-is/strings.xml b/slices/view/src/main/res/values-is/strings.xml
index 855a858..c059c03 100644
--- a/slices/view/src/main/res/values-is/strings.xml
+++ b/slices/view/src/main/res/values-is/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Meira"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Sýna meira"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Uppfært <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one">Fyrir <xliff:g id="ID_2">%d</xliff:g> mín.</item>
- <item quantity="other">Fyrir <xliff:g id="ID_2">%d</xliff:g> mín.</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one">Fyrir <xliff:g id="ID_2">%d</xliff:g> ári</item>
- <item quantity="other">Fyrir <xliff:g id="ID_2">%d</xliff:g> árum</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one">Fyrir <xliff:g id="ID_2">%d</xliff:g> degi</item>
- <item quantity="other">Fyrir <xliff:g id="ID_2">%d</xliff:g> dögum</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Tenging mistókst"</string>
</resources>
diff --git a/slices/view/src/main/res/values-it/strings.xml b/slices/view/src/main/res/values-it/strings.xml
index d2f7a39..05410e8 100644
--- a/slices/view/src/main/res/values-it/strings.xml
+++ b/slices/view/src/main/res/values-it/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Altro"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Mostra altro"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Aggiornamento: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min fa</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> min fa</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> anni fa</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> anno fa</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> gg fa</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> g fa</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Impossibile collegarsi"</string>
</resources>
diff --git a/slices/view/src/main/res/values-iw/strings.xml b/slices/view/src/main/res/values-iw/strings.xml
index db052e3..5c55fe2 100644
--- a/slices/view/src/main/res/values-iw/strings.xml
+++ b/slices/view/src/main/res/values-iw/strings.xml
@@ -21,23 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"עוד"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"הצג יותר"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"עודכן ב-<xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="two">לפני <xliff:g id="ID_2">%d</xliff:g> דק’</item>
- <item quantity="many">לפני <xliff:g id="ID_2">%d</xliff:g> דק’</item>
- <item quantity="other">לפני <xliff:g id="ID_2">%d</xliff:g> דק’</item>
- <item quantity="one">לפני <xliff:g id="ID_1">%d</xliff:g> דק’</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="two">לפני <xliff:g id="ID_2">%d</xliff:g> שנים</item>
- <item quantity="many">לפני <xliff:g id="ID_2">%d</xliff:g> שנים</item>
- <item quantity="other">לפני <xliff:g id="ID_2">%d</xliff:g> שנים</item>
- <item quantity="one">לפני שנה (<xliff:g id="ID_1">%d</xliff:g>)</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="two">לפני <xliff:g id="ID_2">%d</xliff:g> ימים</item>
- <item quantity="many">לפני <xliff:g id="ID_2">%d</xliff:g> ימים</item>
- <item quantity="other">לפני <xliff:g id="ID_2">%d</xliff:g> ימים</item>
- <item quantity="one">לפני יום אחד (<xliff:g id="ID_1">%d</xliff:g>)</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"לא ניתן היה להתחבר"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ja/strings.xml b/slices/view/src/main/res/values-ja/strings.xml
index 4d21cdf..286949f 100644
--- a/slices/view/src/main/res/values-ja/strings.xml
+++ b/slices/view/src/main/res/values-ja/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"もっと見る"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"もっと見る"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"更新時刻: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> 分前</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> 分前</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> 年前</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> 年前</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> 日前</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> 日前</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"接続できませんでした"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ka/strings.xml b/slices/view/src/main/res/values-ka/strings.xml
index 9b8558c..542c6cc 100644
--- a/slices/view/src/main/res/values-ka/strings.xml
+++ b/slices/view/src/main/res/values-ka/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"მეტი"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"მეტის ჩვენება"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"განახლების დრო: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> წუთის წინ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> წუთის წინ</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> წლის წინ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> წლის წინ</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> დღის წინ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> დღის წინ</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"დაკავშირება ვერ მოხერხდა"</string>
</resources>
diff --git a/slices/view/src/main/res/values-kk/strings.xml b/slices/view/src/main/res/values-kk/strings.xml
index 72b0303..231a499 100644
--- a/slices/view/src/main/res/values-kk/strings.xml
+++ b/slices/view/src/main/res/values-kk/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Тағы"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Толығырақ көрсету"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Жаңартылған уақыты: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> минут бұрын</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> минут бұрын</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> жыл бұрын</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> жыл бұрын</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> күн бұрын</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> күн бұрын</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Байланыс орнатылмады"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ko/strings.xml b/slices/view/src/main/res/values-ko/strings.xml
index 4dab983..1ec58f0 100644
--- a/slices/view/src/main/res/values-ko/strings.xml
+++ b/slices/view/src/main/res/values-ko/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"더보기"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"더보기"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g>에 업데이트됨"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g>분 전</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g>분 전</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g>년 전</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g>년 전</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g>일 전</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g>일 전</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"연결할 수 없음"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ky/strings.xml b/slices/view/src/main/res/values-ky/strings.xml
index 63c7d13..06244ab 100644
--- a/slices/view/src/main/res/values-ky/strings.xml
+++ b/slices/view/src/main/res/values-ky/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Дагы"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Дагы көрсөтүү"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> жаңыртылды"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> мүн. мурун</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> мүн. мурун</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> жыл мурун</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> жыл мурун</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> күн мурун</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> күн мурун</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Туташпай койду"</string>
</resources>
diff --git a/slices/view/src/main/res/values-lo/strings.xml b/slices/view/src/main/res/values-lo/strings.xml
index 89c4291..44111ea 100644
--- a/slices/view/src/main/res/values-lo/strings.xml
+++ b/slices/view/src/main/res/values-lo/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"ເພີ່ມເຕີມ"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"ສະແດງເພີ່ມເຕີມ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"ອັບເດດເມື່ອ <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ນທ ກ່ອນ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ນທ ກ່ອນ</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ປີກ່ອນ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ປີກ່ອນ</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ມື້ກ່ອນ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ມື້ກ່ອນ</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້"</string>
</resources>
diff --git a/slices/view/src/main/res/values-mn/strings.xml b/slices/view/src/main/res/values-mn/strings.xml
index 52a5d1a..beaa1a3 100644
--- a/slices/view/src/main/res/values-mn/strings.xml
+++ b/slices/view/src/main/res/values-mn/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Бусад"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Дэлгэрэнгүй үзэх"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> шинэчилсэн"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> минутын өмнө</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> минутын өмнө</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> жилийн өмнө</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> жилийн өмнө</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> өдрийн өмнө</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> өдрийн өмнө</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Холбогдож чадсангүй"</string>
</resources>
diff --git a/slices/view/src/main/res/values-mr/strings.xml b/slices/view/src/main/res/values-mr/strings.xml
index 80aa0a7..693c821 100644
--- a/slices/view/src/main/res/values-mr/strings.xml
+++ b/slices/view/src/main/res/values-mr/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"आणखी"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"आणखी दाखवा"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> ला अपडेट केले"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> मिनिटापूर्वी</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> मिनिटांपूर्वी</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> वर्षापूर्वी</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> वर्षांपूर्वी</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> दिवसापूर्वी</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> दिवसांपूर्वी</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"कनेक्ट करता आले नाही"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ms/strings.xml b/slices/view/src/main/res/values-ms/strings.xml
index 576b8df..eced3de 100644
--- a/slices/view/src/main/res/values-ms/strings.xml
+++ b/slices/view/src/main/res/values-ms/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Lagi"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Tunjukkan lagi"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Dikemas kini pada <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min yang lalu</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> min yang lalu</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> thn yang lalu</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> thn yang lalu</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> hari yang lalu</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> hari yang lalu</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Tidak dapat menyambung"</string>
</resources>
diff --git a/slices/view/src/main/res/values-nb/strings.xml b/slices/view/src/main/res/values-nb/strings.xml
index 3fad9c4..6576626 100644
--- a/slices/view/src/main/res/values-nb/strings.xml
+++ b/slices/view/src/main/res/values-nb/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Mer"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Vis mer"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Oppdatert <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other">For <xliff:g id="ID_2">%d</xliff:g> min. siden</item>
- <item quantity="one">For <xliff:g id="ID_1">%d</xliff:g> min. siden</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other">For <xliff:g id="ID_2">%d</xliff:g> år siden</item>
- <item quantity="one">For <xliff:g id="ID_1">%d</xliff:g> år siden</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other">For <xliff:g id="ID_2">%d</xliff:g> dager siden</item>
- <item quantity="one">For <xliff:g id="ID_1">%d</xliff:g> dag siden</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Kunne ikke koble til"</string>
</resources>
diff --git a/slices/view/src/main/res/values-nl/strings.xml b/slices/view/src/main/res/values-nl/strings.xml
index b5d2edc..1ba58e9 100644
--- a/slices/view/src/main/res/values-nl/strings.xml
+++ b/slices/view/src/main/res/values-nl/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Meer"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Meer weergeven"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Geüpdatet: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min geleden</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> min geleden</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> jaar geleden</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> jaar geleden</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> dagen geleden</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> dag geleden</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Kan geen verbinding maken"</string>
</resources>
diff --git a/slices/view/src/main/res/values-or/strings.xml b/slices/view/src/main/res/values-or/strings.xml
index 6bf6019..1099e80 100644
--- a/slices/view/src/main/res/values-or/strings.xml
+++ b/slices/view/src/main/res/values-or/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"ଅଧିକ"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"ଅଧିକ ଦେଖାନ୍ତୁ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g>ରେ ଅପଡେଟ୍ ହୋଇଥିଲା"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ମିନିଟ୍ ପୂର୍ବେ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ମିନିଟ୍ ପୂର୍ବେ</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ବର୍ଷ ପୂର୍ବେ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ବର୍ଷ ପୂର୍ବେ</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ଦିନ ପୂର୍ବେ</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ଦିନ ପୂର୍ବେ</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"କନେକ୍ଟ ହେଲାନାହିଁ"</string>
</resources>
diff --git a/slices/view/src/main/res/values-pa/strings.xml b/slices/view/src/main/res/values-pa/strings.xml
index e588aac..8926d0f 100644
--- a/slices/view/src/main/res/values-pa/strings.xml
+++ b/slices/view/src/main/res/values-pa/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"ਹੋਰ"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"ਹੋਰ ਦਿਖਾਓ"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> ਅੱਪਡੇਟ ਕੀਤੀ ਗਈ"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> ਮਿੰਟ ਪਹਿਲਾਂ</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ਮਿੰਟ ਪਹਿਲਾਂ</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> ਸਾਲ ਪਹਿਲਾਂ</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ਸਾਲ ਪਹਿਲਾਂ</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> ਦਿਨ ਪਹਿਲਾਂ</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ਦਿਨ ਪਹਿਲਾਂ</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
</resources>
diff --git a/slices/view/src/main/res/values-pl/strings.xml b/slices/view/src/main/res/values-pl/strings.xml
index c5300ca..fa565f3 100644
--- a/slices/view/src/main/res/values-pl/strings.xml
+++ b/slices/view/src/main/res/values-pl/strings.xml
@@ -21,23 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Więcej"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Pokaż więcej"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Aktualizacja: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="few"><xliff:g id="ID_2">%d</xliff:g> min temu</item>
- <item quantity="many"><xliff:g id="ID_2">%d</xliff:g> min temu</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> min temu</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> min temu</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="few"><xliff:g id="ID_2">%d</xliff:g> lata temu</item>
- <item quantity="many"><xliff:g id="ID_2">%d</xliff:g> lat temu</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> roku temu</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> rok temu</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="few"><xliff:g id="ID_2">%d</xliff:g> dni temu</item>
- <item quantity="many"><xliff:g id="ID_2">%d</xliff:g> dni temu</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> dnia temu</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> dzień temu</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Nie udało się połączyć"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ro/strings.xml b/slices/view/src/main/res/values-ro/strings.xml
index 9ff89d0..a3f9ff2 100644
--- a/slices/view/src/main/res/values-ro/strings.xml
+++ b/slices/view/src/main/res/values-ro/strings.xml
@@ -22,19 +22,19 @@
<string name="abc_slice_show_more" msgid="1567717014004692768">"Vedeți mai multe"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Actualizat la <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="few">acum <xliff:g id="ID_2">%d</xliff:g> min.</item>
- <item quantity="other">acum <xliff:g id="ID_2">%d</xliff:g> de min.</item>
- <item quantity="one">acum <xliff:g id="ID_1">%d</xliff:g> min.</item>
+ <item quantity="few">Acum <xliff:g id="ID_2">%d</xliff:g> min.</item>
+ <item quantity="other">Acum <xliff:g id="ID_2">%d</xliff:g> de min.</item>
+ <item quantity="one">Acum <xliff:g id="ID_1">%d</xliff:g> min.</item>
</plurals>
<plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="few">acum <xliff:g id="ID_2">%d</xliff:g> ani</item>
- <item quantity="other">acum <xliff:g id="ID_2">%d</xliff:g> de ani</item>
- <item quantity="one">acum <xliff:g id="ID_1">%d</xliff:g> an</item>
+ <item quantity="few">Acum <xliff:g id="ID_2">%d</xliff:g> ani</item>
+ <item quantity="other">Acum <xliff:g id="ID_2">%d</xliff:g> de ani</item>
+ <item quantity="one">Acum <xliff:g id="ID_1">%d</xliff:g> an</item>
</plurals>
<plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="few">acum <xliff:g id="ID_2">%d</xliff:g> zile</item>
- <item quantity="other">acum <xliff:g id="ID_2">%d</xliff:g> de zile</item>
- <item quantity="one">acum <xliff:g id="ID_1">%d</xliff:g> zi</item>
+ <item quantity="few">Acum <xliff:g id="ID_2">%d</xliff:g> zile</item>
+ <item quantity="other">Acum <xliff:g id="ID_2">%d</xliff:g> de zile</item>
+ <item quantity="one">Acum <xliff:g id="ID_1">%d</xliff:g> zi</item>
</plurals>
<string name="abc_slice_error" msgid="4188371422904147368">"Nu s-a putut conecta"</string>
</resources>
diff --git a/slices/view/src/main/res/values-si/strings.xml b/slices/view/src/main/res/values-si/strings.xml
index cfd7685..be85112 100644
--- a/slices/view/src/main/res/values-si/strings.xml
+++ b/slices/view/src/main/res/values-si/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"තව"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"තව පෙන්වන්න"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> යාවත්කාලීන කරන ලදී"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one">මිනි <xliff:g id="ID_2">%d</xliff:g>කට පෙර</item>
- <item quantity="other">මිනි <xliff:g id="ID_2">%d</xliff:g>කට පෙර</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="one">වසර <xliff:g id="ID_2">%d</xliff:g>කට පෙර</item>
- <item quantity="other">වසර <xliff:g id="ID_2">%d</xliff:g>කට පෙර</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="one">දින <xliff:g id="ID_2">%d</xliff:g>කට පෙර</item>
- <item quantity="other">දින <xliff:g id="ID_2">%d</xliff:g>කට පෙර</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"සම්බන්ධ වීමට නොහැකි විය"</string>
</resources>
diff --git a/slices/view/src/main/res/values-sk/strings.xml b/slices/view/src/main/res/values-sk/strings.xml
index 76bed58..a153760 100644
--- a/slices/view/src/main/res/values-sk/strings.xml
+++ b/slices/view/src/main/res/values-sk/strings.xml
@@ -22,22 +22,22 @@
<string name="abc_slice_show_more" msgid="1567717014004692768">"Zobraziť viac"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Aktualizované <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="few">pred <xliff:g id="ID_2">%d</xliff:g> min</item>
- <item quantity="many">pred <xliff:g id="ID_2">%d</xliff:g> min</item>
- <item quantity="other">pred <xliff:g id="ID_2">%d</xliff:g> min</item>
- <item quantity="one">pred <xliff:g id="ID_1">%d</xliff:g> min</item>
+ <item quantity="few">Pred <xliff:g id="ID_2">%d</xliff:g> min</item>
+ <item quantity="many">Pred <xliff:g id="ID_2">%d</xliff:g> min</item>
+ <item quantity="other">Pred <xliff:g id="ID_2">%d</xliff:g> min</item>
+ <item quantity="one">Pred <xliff:g id="ID_1">%d</xliff:g> min</item>
</plurals>
<plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="few">pred <xliff:g id="ID_2">%d</xliff:g> rokmi</item>
- <item quantity="many">pred <xliff:g id="ID_2">%d</xliff:g> roka</item>
- <item quantity="other">pred <xliff:g id="ID_2">%d</xliff:g> rokmi</item>
- <item quantity="one">pred <xliff:g id="ID_1">%d</xliff:g> rokom</item>
+ <item quantity="few">Pred <xliff:g id="ID_2">%d</xliff:g> rokmi</item>
+ <item quantity="many">Pred <xliff:g id="ID_2">%d</xliff:g> rokom</item>
+ <item quantity="other">Pred <xliff:g id="ID_2">%d</xliff:g> rokmi</item>
+ <item quantity="one">Pred <xliff:g id="ID_1">%d</xliff:g> rokom</item>
</plurals>
<plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="few">pred <xliff:g id="ID_2">%d</xliff:g> dňami</item>
- <item quantity="many">pred <xliff:g id="ID_2">%d</xliff:g> dňa</item>
- <item quantity="other">pred <xliff:g id="ID_2">%d</xliff:g> dňami</item>
- <item quantity="one">pred <xliff:g id="ID_1">%d</xliff:g> dňom</item>
+ <item quantity="few">Pred <xliff:g id="ID_2">%d</xliff:g> dňami</item>
+ <item quantity="many">Pred <xliff:g id="ID_2">%d</xliff:g> dňami</item>
+ <item quantity="other">Pred <xliff:g id="ID_2">%d</xliff:g> dňami</item>
+ <item quantity="one">Pred <xliff:g id="ID_1">%d</xliff:g> dňom</item>
</plurals>
<string name="abc_slice_error" msgid="4188371422904147368">"Nepodarilo sa pripojiť"</string>
</resources>
diff --git a/slices/view/src/main/res/values-sv/strings.xml b/slices/view/src/main/res/values-sv/strings.xml
index 90caa1a..bc6947d 100644
--- a/slices/view/src/main/res/values-sv/strings.xml
+++ b/slices/view/src/main/res/values-sv/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Mer"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Visa mer"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Uppdaterades <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> minuter sedan</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> minut sedan</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> år sedan</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> år sedan</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> dagar sedan</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> dag sedan</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Det gick inte att ansluta"</string>
</resources>
diff --git a/slices/view/src/main/res/values-ta/strings.xml b/slices/view/src/main/res/values-ta/strings.xml
index 778218e..5b36b79 100644
--- a/slices/view/src/main/res/values-ta/strings.xml
+++ b/slices/view/src/main/res/values-ta/strings.xml
@@ -20,18 +20,11 @@
<string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="abc_slice_more" msgid="1983560225998630901">"மேலும்"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"மேலும் காட்டு"</string>
- <string name="abc_slice_updated" msgid="8155085405396453848">"புதுப்பித்தது: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> நிமி. முன்</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> நிமி. முன்</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ஆண்டிற்கு முன்</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ஆண்டிற்கு முன்</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> நாளுக்கு முன்</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> நாளுக்கு முன்</item>
- </plurals>
- <string name="abc_slice_error" msgid="4188371422904147368">"இணைக்க முடியவில்லை"</string>
+ <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+ <skip />
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
+ <!-- no translation found for abc_slice_error (4188371422904147368) -->
+ <skip />
</resources>
diff --git a/slices/view/src/main/res/values-tl/strings.xml b/slices/view/src/main/res/values-tl/strings.xml
index 2e76a1a..d2d5526 100644
--- a/slices/view/src/main/res/values-tl/strings.xml
+++ b/slices/view/src/main/res/values-tl/strings.xml
@@ -22,8 +22,8 @@
<string name="abc_slice_show_more" msgid="1567717014004692768">"Magpakita pa"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Na-update noong <xliff:g id="TIME">%1$s</xliff:g>"</string>
<plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> min ang nakalipas</item>
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> na min ang nakalipas</item>
+ <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> minuto ang nakalipas</item>
+ <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> na minuto ang nakalipas</item>
</plurals>
<plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
<item quantity="one"><xliff:g id="ID_2">%d</xliff:g> taon ang nakalipas</item>
diff --git a/slices/view/src/main/res/values-ur/strings.xml b/slices/view/src/main/res/values-ur/strings.xml
index 1fff81c..4f51700 100644
--- a/slices/view/src/main/res/values-ur/strings.xml
+++ b/slices/view/src/main/res/values-ur/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"مزید"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"مزید دکھائیں"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"<xliff:g id="TIME">%1$s</xliff:g> اپ ڈیٹ کیا گیا"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> منٹ پہلے</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> منٹ پہلے</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> سال پہلے</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> سال پہلے</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> دن پہلے</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> دن پہلے</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"منسلک نہیں ہو سکا"</string>
</resources>
diff --git a/slices/view/src/main/res/values-uz/strings.xml b/slices/view/src/main/res/values-uz/strings.xml
index 0a973cd..2250c91 100644
--- a/slices/view/src/main/res/values-uz/strings.xml
+++ b/slices/view/src/main/res/values-uz/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Yana"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Yana"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Yangilandi: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> daqiqa oldin</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> daqiqa oldin</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> yil oldin</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> yil oldin</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> kun oldin</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> kun oldin</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Ulanib bo‘lmadi"</string>
</resources>
diff --git a/slices/view/src/main/res/values-vi/strings.xml b/slices/view/src/main/res/values-vi/strings.xml
index 1e71db6..c9129be 100644
--- a/slices/view/src/main/res/values-vi/strings.xml
+++ b/slices/view/src/main/res/values-vi/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"Thêm"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"Hiển thị thêm"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"Đã cập nhật lúc <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> phút trước</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> phút trước</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> năm trước</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> năm trước</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> ngày trước</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> ngày trước</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"Không thể kết nối"</string>
</resources>
diff --git a/slices/view/src/main/res/values-zh-rCN/strings.xml b/slices/view/src/main/res/values-zh-rCN/strings.xml
index c018343..2ecb835 100644
--- a/slices/view/src/main/res/values-zh-rCN/strings.xml
+++ b/slices/view/src/main/res/values-zh-rCN/strings.xml
@@ -21,17 +21,8 @@
<string name="abc_slice_more" msgid="1983560225998630901">"更多"</string>
<string name="abc_slice_show_more" msgid="1567717014004692768">"显示更多"</string>
<string name="abc_slice_updated" msgid="8155085405396453848">"更新时间:<xliff:g id="TIME">%1$s</xliff:g>"</string>
- <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> 分钟前</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> 分钟前</item>
- </plurals>
- <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> 年前</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> 年前</item>
- </plurals>
- <plurals name="abc_slice_duration_days" formatted="false" msgid="6241698511167107334">
- <item quantity="other"><xliff:g id="ID_2">%d</xliff:g> 天前</item>
- <item quantity="one"><xliff:g id="ID_1">%d</xliff:g> 天前</item>
- </plurals>
+ <!-- no translation found for abc_slice_duration_min (6996334305156847955) -->
+ <!-- no translation found for abc_slice_duration_years (6212691832333991589) -->
+ <!-- no translation found for abc_slice_duration_days (6241698511167107334) -->
<string name="abc_slice_error" msgid="4188371422904147368">"无法连接"</string>
</resources>
diff --git a/testutils/build.gradle b/testutils/build.gradle
index e0c4139..f39248e 100644
--- a/testutils/build.gradle
+++ b/testutils/build.gradle
@@ -36,3 +36,7 @@
disable 'InvalidPackage' // Lint is unhappy about junit package
}
}
+
+supportLibrary {
+ failOnUncheckedWarnings = false
+}
\ No newline at end of file
diff --git a/textclassifier/build.gradle b/textclassifier/build.gradle
index fd654ee..fcaa89d 100644
--- a/textclassifier/build.gradle
+++ b/textclassifier/build.gradle
@@ -24,4 +24,5 @@
inceptionYear = "2018"
description = "The TextClassifier Support Library can be added to an Android application in order to use the TextClassifier API introduced in Android O on all devices with API level 14 or later."
minSdkVersion = 14
+ failOnUncheckedWarnings = false
}
diff --git a/transition/build.gradle b/transition/build.gradle
index 3e4e7d1..61c690f 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -36,4 +36,5 @@
mavenGroup = LibraryGroups.TRANSITION
inceptionYear = "2016"
description = "Android Transition Support Library"
+ failOnDeprecationWarnings = false
}
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index 9fe5f93..469f06d 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -23,4 +23,6 @@
inceptionYear = "2017"
description = "Android Support Library for TV Provider"
minSdkVersion = 21
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
\ No newline at end of file
diff --git a/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractUtils.java b/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractUtils.java
index 3483d0f..99383c0 100644
--- a/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractUtils.java
+++ b/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractUtils.java
@@ -50,7 +50,7 @@
if (TextUtils.isEmpty(commaSeparatedRatings)) {
return EMPTY;
}
- String[] ratings = commaSeparatedRatings.split("\\s*,\\s*");
+ String[] ratings = commaSeparatedRatings.split("\\s*,\\s*", -1);
List<TvContentRating> contentRatings = new ArrayList<>(ratings.length);
for (String rating : ratings) {
try {
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index a2ca59a..b04bee6 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -53,4 +53,6 @@
mavenGroup = LibraryGroups.APPCOMPAT
inceptionYear = "2011"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/v7/appcompat/res/values-bs/strings.xml b/v7/appcompat/res/values-bs/strings.xml
index 5100cbf..91281fc 100644
--- a/v7/appcompat/res/values-bs/strings.xml
+++ b/v7/appcompat/res/values-bs/strings.xml
@@ -20,7 +20,7 @@
<string name="abc_action_bar_home_description" msgid="4600421777120114993">"Vrati se na početnu stranicu"</string>
<string name="abc_action_bar_up_description" msgid="1594238315039666878">"Navigiraj prema gore"</string>
<string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Više opcija"</string>
- <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"Suzi"</string>
+ <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"Skupi"</string>
<string name="abc_searchview_description_search" msgid="8264924765203268293">"Traži"</string>
<string name="abc_search_hint" msgid="7723749260725869598">"Pretraži..."</string>
<string name="abc_searchview_description_query" msgid="2550479030709304392">"Pretraži upit"</string>
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java b/v7/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java
index b66dec3..404df41 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java
@@ -39,6 +39,7 @@
import androidx.annotation.RestrictTo;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.Toolbar;
+import androidx.appcompat.widget.VectorEnabledTintResources;
import androidx.core.view.WindowCompat;
import androidx.fragment.app.FragmentActivity;
@@ -129,8 +130,6 @@
@NightMode
private static int sDefaultNightMode = MODE_NIGHT_FOLLOW_SYSTEM;
- private static boolean sCompatVectorFromResourcesEnabled = false;
-
/** @hide */
@RestrictTo(LIBRARY_GROUP)
@IntDef({MODE_NIGHT_NO, MODE_NIGHT_YES, MODE_NIGHT_AUTO, MODE_NIGHT_FOLLOW_SYSTEM,
@@ -522,7 +521,7 @@
* <p>Please note: this only takes effect in Activities created after this call.</p>
*/
public static void setCompatVectorFromResourcesEnabled(boolean enabled) {
- sCompatVectorFromResourcesEnabled = enabled;
+ VectorEnabledTintResources.setCompatVectorFromResourcesEnabled(enabled);
}
/**
@@ -532,6 +531,6 @@
* @see #setCompatVectorFromResourcesEnabled(boolean)
*/
public static boolean isCompatVectorFromResourcesEnabled() {
- return sCompatVectorFromResourcesEnabled;
+ return VectorEnabledTintResources.isCompatVectorFromResourcesEnabled();
}
}
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/VectorEnabledTintResources.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/VectorEnabledTintResources.java
index 15fcf88..af61860 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/VectorEnabledTintResources.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/VectorEnabledTintResources.java
@@ -25,7 +25,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
-import androidx.appcompat.app.AppCompatDelegate;
import java.lang.ref.WeakReference;
@@ -37,9 +36,10 @@
*/
@RestrictTo(LIBRARY_GROUP)
public class VectorEnabledTintResources extends Resources {
+ private static boolean sCompatVectorFromResourcesEnabled = false;
public static boolean shouldBeUsed() {
- return AppCompatDelegate.isCompatVectorFromResourcesEnabled()
+ return isCompatVectorFromResourcesEnabled()
&& Build.VERSION.SDK_INT <= MAX_SDK_WHERE_REQUIRED;
}
@@ -74,4 +74,22 @@
final Drawable superGetDrawable(int id) {
return super.getDrawable(id);
}
+
+ /**
+ * Sets whether vector drawables on older platforms (< API 21) can be used within
+ * {@link android.graphics.drawable.DrawableContainer} resources.
+ */
+ public static void setCompatVectorFromResourcesEnabled(boolean enabled) {
+ sCompatVectorFromResourcesEnabled = enabled;
+ }
+
+ /**
+ * Returns whether vector drawables on older platforms (< API 21) can be accessed from within
+ * resources.
+ *
+ * @see #setCompatVectorFromResourcesEnabled(boolean)
+ */
+ public static boolean isCompatVectorFromResourcesEnabled() {
+ return sCompatVectorFromResourcesEnabled;
+ }
}
\ No newline at end of file
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 3e93b4e..ab5b778 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -42,4 +42,6 @@
mavenGroup = LibraryGroups.RECYCLERVIEW
inceptionYear = "2014"
description = "Android Support RecyclerView v7"
+ failOnUncheckedWarnings = false
+ failOnDeprecationWarnings = false
}
diff --git a/viewpager/build.gradle b/viewpager/build.gradle
index 02b45ba..6ba1d4d 100644
--- a/viewpager/build.gradle
+++ b/viewpager/build.gradle
@@ -24,4 +24,5 @@
mavenGroup = LibraryGroups.VIEWPAGER
inceptionYear = "2018"
description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+ failOnDeprecationWarnings = false
}
diff --git a/wear/build.gradle b/wear/build.gradle
index c70ebef..0f606f1 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -42,4 +42,5 @@
inceptionYear = "2016"
description = "Android Wear Support UI"
minSdkVersion = 23
+ failOnDeprecationWarnings = false
}
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index 08c6a55..60dbb9c 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -1,5 +1,11 @@
package androidx.webkit {
+ public abstract class SafeBrowsingResponseCompat {
+ method public abstract void backToSafety(boolean);
+ method public abstract void proceed(boolean);
+ method public abstract void showInterstitial(boolean);
+ }
+
public abstract class ServiceWorkerClientCompat {
ctor public ServiceWorkerClientCompat();
method public abstract android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
@@ -22,6 +28,15 @@
method public abstract void setCacheMode(int);
}
+ public abstract class WebResourceErrorCompat {
+ method public abstract java.lang.CharSequence getDescription();
+ method public abstract int getErrorCode();
+ }
+
+ public class WebResourceRequestCompat {
+ method public static boolean isRedirect(android.webkit.WebResourceRequest);
+ }
+
public class WebSettingsCompat {
method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
@@ -33,6 +48,10 @@
public class WebViewClientCompat extends android.webkit.WebViewClient {
ctor public WebViewClientCompat();
+ method public final void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
+ method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, androidx.webkit.WebResourceErrorCompat);
+ method public final void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
+ method public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, androidx.webkit.SafeBrowsingResponseCompat);
}
public class WebViewCompat {
@@ -49,7 +68,24 @@
public class WebViewFeature {
method public static boolean isFeatureSupported(java.lang.String);
+ field public static final java.lang.String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
+ field public static final java.lang.String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
+ field public static final java.lang.String RECEIVE_HTTP_ERROR = "RECEIVE_HTTP_ERROR";
+ field public static final java.lang.String RECEIVE_WEB_RESOURCE_ERROR = "RECEIVE_WEB_RESOURCE_ERROR";
+ field public static final java.lang.String SAFE_BROWSING_ENABLE = "SAFE_BROWSING_ENABLE";
+ field public static final java.lang.String SAFE_BROWSING_HIT = "SAFE_BROWSING_HIT";
+ field public static final java.lang.String SAFE_BROWSING_PRIVACY_POLICY_URL = "SAFE_BROWSING_PRIVACY_POLICY_URL";
+ field public static final java.lang.String SAFE_BROWSING_WHITELIST = "SAFE_BROWSING_WHITELIST";
+ field public static final java.lang.String SERVICE_WORKER_BASIC_USAGE = "SERVICE_WORKER_BASIC_USAGE";
+ field public static final java.lang.String SERVICE_WORKER_BLOCK_NETWORK_LOADS = "SERVICE_WORKER_BLOCK_NETWORK_LOADS";
+ field public static final java.lang.String SERVICE_WORKER_CACHE_MODE = "SERVICE_WORKER_CACHE_MODE";
+ field public static final java.lang.String SERVICE_WORKER_CONTENT_ACCESS = "SERVICE_WORKER_CONTENT_ACCESS";
+ field public static final java.lang.String SERVICE_WORKER_FILE_ACCESS = "SERVICE_WORKER_FILE_ACCESS";
+ field public static final java.lang.String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST = "SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST";
+ field public static final java.lang.String SHOULD_OVERRIDE_WITH_REDIRECTS = "SHOULD_OVERRIDE_WITH_REDIRECTS";
+ field public static final java.lang.String START_SAFE_BROWSING = "START_SAFE_BROWSING";
field public static final java.lang.String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+ field public static final java.lang.String WEB_RESOURCE_REQUEST_IS_REDIRECT = "WEB_RESOURCE_REQUEST_IS_REDIRECT";
}
}
diff --git a/webkit/build.gradle b/webkit/build.gradle
index d610dad..baed9cb 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -40,7 +40,7 @@
}
buildTypes.all {
- consumerProguardFiles new File(webviewBoundaryInterfacesDir, "proguard.flags")
+ consumerProguardFiles new File(webviewBoundaryInterfacesDir, "proguard.flags") , 'proguard-rules.pro'
}
}
diff --git a/webkit/proguard-rules.pro b/webkit/proguard-rules.pro
new file mode 100644
index 0000000..86756ab
--- /dev/null
+++ b/webkit/proguard-rules.pro
@@ -0,0 +1,16 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Prevent WebViewClientCompat from being renamed, since chromium depends on this name.
+-keep public class androidx.webkit.WebViewClientCompat { public *; }
diff --git a/webkit/src/androidTest/java/androidx/webkit/IncompatibilityTest.java b/webkit/src/androidTest/java/androidx/webkit/IncompatibilityTest.java
new file mode 100644
index 0000000..09424c6
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/IncompatibilityTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.runner.AndroidJUnit4;
+
+import androidx.webkit.internal.WebViewFeatureInternal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests ensuring that Android versions/setups that are incompatible with the WebView Support
+ * Library are handled gracefully.
+ *
+ * Only L+ Android versions are compatible with the WebView Support Library, so any tests in this
+ * class that guarantee certain behaviour for incompatible Android versions will only be run on
+ * pre-L devices.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class IncompatibilityTest {
+ @Test
+ @SdkSuppress(maxSdkVersion = 20)
+ public void testPreLDeviceHasNoWebViewFeatures() {
+ assertEquals(0, WebViewFeatureInternal.getWebViewApkFeaturesForTesting().length);
+ }
+
+ @Test
+ @SdkSuppress(maxSdkVersion = 20)
+ public void testPreLDeviceDoesNotSupportVisualStateCallback() {
+ assertFalse(WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK));
+ }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
index bd77fdb..893b6df 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -29,7 +29,6 @@
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
import android.webkit.SafeBrowsingResponse;
import android.webkit.ValueCallback;
@@ -85,9 +84,12 @@
assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
}
- @Suppress // TODO(gsennton) remove @Suppress when b/76202025 has been resolved
@Test
public void testCheckThread() {
+ if (!WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK)) {
+ // Skip this test if VisualStateCallback is not supported.
+ return;
+ }
try {
WebViewCompat.postVisualStateCallback(mWebViewOnUiThread.getWebViewOnCurrentThread(), 5,
new WebViewCompat.VisualStateCallback() {
diff --git a/webkit/src/main/java/androidx/webkit/SafeBrowsingResponseCompat.java b/webkit/src/main/java/androidx/webkit/SafeBrowsingResponseCompat.java
new file mode 100644
index 0000000..67e046a
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/SafeBrowsingResponseCompat.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.webkit.SafeBrowsingResponse;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import org.chromium.support_lib_boundary.SafeBrowsingResponseBoundaryInterface;
+import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
+
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * Compatibility version of {@link SafeBrowsingResponse}.
+ */
+public abstract class SafeBrowsingResponseCompat {
+ /**
+ * Display the default interstitial.
+ *
+ * @param allowReporting {@code true} if the interstitial should show a reporting checkbox.
+ */
+ public abstract void showInterstitial(boolean allowReporting);
+
+ /**
+ * Act as if the user clicked "visit this unsafe site."
+ *
+ * @param report {@code true} to enable Safe Browsing reporting.
+ */
+ public abstract void proceed(boolean report);
+
+ /**
+ * Act as if the user clicked "back to safety."
+ *
+ * @param report {@code true} to enable Safe Browsing reporting.
+ */
+ public abstract void backToSafety(boolean report);
+
+ /**
+ * This class cannot be created by applications. The support library should instantiate this
+ * with {@link #fromInvocationHandler} or {@link #fromSafeBrowsingResponse}.
+ */
+ private SafeBrowsingResponseCompat() {
+ }
+
+ /**
+ * Conversion helper to create a SafeBrowsingResponseCompat which delegates calls to {@param
+ * handler}. The InvocationHandler must be created by {@link
+ * BoundaryInterfaceReflectionUtil#createInvocationHandlerFor} using {@link
+ * SafeBrowsingResponseBoundaryInterface}.
+ *
+ * @param handler The InvocationHandler that chromium passed in the callback.
+ */
+ @NonNull
+ /* package */ static SafeBrowsingResponseCompat fromInvocationHandler(
+ @NonNull InvocationHandler handler) {
+ final SafeBrowsingResponseBoundaryInterface responseDelegate =
+ BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ SafeBrowsingResponseBoundaryInterface.class, handler);
+ return new SafeBrowsingResponseCompat() {
+ @Override
+ public void showInterstitial(boolean allowReporting) {
+ responseDelegate.showInterstitial(allowReporting);
+ }
+
+ @Override
+ public void proceed(boolean report) {
+ responseDelegate.proceed(report);
+ }
+
+ @Override
+ public void backToSafety(boolean report) {
+ responseDelegate.backToSafety(report);
+ }
+ };
+ }
+
+ /**
+ * Conversion helper to create a SafeBrowsingResponseCompat which delegates calls to {@param
+ * response}.
+ *
+ * @param response The SafeBrowsingResponse that chromium passed in the callback.
+ */
+ @NonNull
+ @RequiresApi(27)
+ /* package */ static SafeBrowsingResponseCompat fromSafeBrowsingResponse(
+ @NonNull final SafeBrowsingResponse response) {
+ return new SafeBrowsingResponseCompat() {
+ @Override
+ public void showInterstitial(boolean allowReporting) {
+ response.showInterstitial(allowReporting);
+ }
+
+ @Override
+ public void proceed(boolean report) {
+ response.proceed(report);
+ }
+
+ @Override
+ public void backToSafety(boolean report) {
+ response.backToSafety(report);
+ }
+ };
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
index 19aab8c..5c3c5ff 100644
--- a/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
@@ -43,6 +43,10 @@
* @see android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView,
* WebResourceRequest)
*
+ * This method is called only if
+ * {@link WebViewFeature#SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST} is supported. You can check
+ * whether that flag is supported using {@link WebViewFeature#isFeatureSupported(String)}.
+ *
*/
public abstract WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request);
}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
index 3eb55d2..79b714a 100644
--- a/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
@@ -16,18 +16,11 @@
package androidx.webkit;
-import android.os.Build;
-import android.webkit.ServiceWorkerController;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
-import androidx.webkit.internal.FrameworkServiceWorkerController;
-import androidx.webkit.internal.ServiceWorkerControllerAdapter;
-import androidx.webkit.internal.WebViewGlueCommunicator;
-
-// TODO(gsennton) guard APIs with isFeatureSupported(String)
+import androidx.webkit.internal.ServiceWorkerControllerImpl;
/**
* Manages Service Workers used by WebView.
@@ -61,28 +54,14 @@
* @return the default ServiceWorkerController instance
*/
@NonNull
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_BASIC_USAGE,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static ServiceWorkerControllerCompat getInstance() {
return LAZY_HOLDER.INSTANCE;
}
private static class LAZY_HOLDER {
- static final ServiceWorkerControllerCompat INSTANCE =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
- ? getFrameworkControllerCompat() : getSupportLibraryControllerCompat();
- }
-
- /**
- * Return a version of {@link ServiceWorkerControllerCompat} that only uses framework APIs.
- */
- @RequiresApi(Build.VERSION_CODES.N)
- private static ServiceWorkerControllerCompat getFrameworkControllerCompat() {
- return new FrameworkServiceWorkerController(
- ServiceWorkerController.getInstance());
- }
-
- private static ServiceWorkerControllerCompat getSupportLibraryControllerCompat() {
- return new ServiceWorkerControllerAdapter(
- WebViewGlueCommunicator.getFactory().getServiceWorkerController());
+ static final ServiceWorkerControllerCompat INSTANCE = new ServiceWorkerControllerImpl();
}
/**
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
index 61c46c3..6763db4 100644
--- a/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
@@ -19,6 +19,7 @@
import android.webkit.WebSettings;
import androidx.annotation.IntDef;
+import androidx.annotation.RequiresFeature;
import androidx.annotation.RestrictTo;
import java.lang.annotation.Retention;
@@ -58,6 +59,8 @@
* {@link WebSettings#LOAD_DEFAULT}.
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_CACHE_MODE,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract void setCacheMode(@CacheMode int mode);
/**
@@ -68,6 +71,8 @@
* @see #setCacheMode
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_CACHE_MODE,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract @CacheMode int getCacheMode();
/**
@@ -76,6 +81,8 @@
* {@link WebSettings#setAllowContentAccess}.
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract void setAllowContentAccess(boolean allow);
/**
@@ -85,6 +92,8 @@
* @see #setAllowContentAccess
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract boolean getAllowContentAccess();
/**
@@ -93,6 +102,8 @@
* {@link WebSettings#setAllowFileAccess}.
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_FILE_ACCESS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract void setAllowFileAccess(boolean allow);
/**
@@ -102,6 +113,8 @@
* @see #setAllowFileAccess
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_FILE_ACCESS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract boolean getAllowFileAccess();
/**
@@ -112,6 +125,8 @@
* @param flag {@code true} means block network loads by the Service Workers
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract void setBlockNetworkLoads(boolean flag);
/**
@@ -123,5 +138,7 @@
* @see #setBlockNetworkLoads
*
*/
+ @RequiresFeature(name = WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public abstract boolean getBlockNetworkLoads();
}
diff --git a/webkit/src/main/java/androidx/webkit/WebResourceErrorCompat.java b/webkit/src/main/java/androidx/webkit/WebResourceErrorCompat.java
new file mode 100644
index 0000000..24e2f94
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebResourceErrorCompat.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.webkit.WebResourceError;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+
+import org.chromium.support_lib_boundary.WebResourceErrorBoundaryInterface;
+import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * Compatibility version of {@link WebResourceError}.
+ */
+public abstract class WebResourceErrorCompat {
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @IntDef(value = {
+ WebViewClient.ERROR_UNKNOWN,
+ WebViewClient.ERROR_HOST_LOOKUP,
+ WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME,
+ WebViewClient.ERROR_AUTHENTICATION,
+ WebViewClient.ERROR_PROXY_AUTHENTICATION,
+ WebViewClient.ERROR_CONNECT,
+ WebViewClient.ERROR_IO,
+ WebViewClient.ERROR_TIMEOUT,
+ WebViewClient.ERROR_REDIRECT_LOOP,
+ WebViewClient.ERROR_UNSUPPORTED_SCHEME,
+ WebViewClient.ERROR_FAILED_SSL_HANDSHAKE,
+ WebViewClient.ERROR_BAD_URL,
+ WebViewClient.ERROR_FILE,
+ WebViewClient.ERROR_FILE_NOT_FOUND,
+ WebViewClient.ERROR_TOO_MANY_REQUESTS,
+ WebViewClient.ERROR_UNSAFE_RESOURCE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NetErrorCode {}
+
+ /**
+ * Gets the error code of the error. The code corresponds to one
+ * of the {@code ERROR_*} constants in {@link WebViewClient}.
+ *
+ * @return The error code of the error
+ */
+ public abstract @NetErrorCode int getErrorCode();
+
+ /**
+ * Gets the string describing the error. Descriptions are localized,
+ * and thus can be used for communicating the problem to the user.
+ *
+ * @return The description of the error
+ */
+ @NonNull
+ public abstract CharSequence getDescription();
+
+ /**
+ * This class cannot be created by applications. The support library should instantiate this
+ * with {@link #fromInvocationHandler} or {@link #fromWebResourceError}.
+ */
+ private WebResourceErrorCompat() {
+ }
+
+ /**
+ * Conversion helper to create a WebResourceErrorCompat which delegates calls to {@param
+ * handler}. The InvocationHandler must be created by {@link
+ * BoundaryInterfaceReflectionUtil#createInvocationHandlerFor} using {@link
+ * WebResourceErrorBoundaryInterface}.
+ *
+ * @param handler The InvocationHandler that chromium passed in the callback.
+ */
+ @NonNull
+ /* package */ static WebResourceErrorCompat fromInvocationHandler(
+ @NonNull InvocationHandler handler) {
+ final WebResourceErrorBoundaryInterface errorDelegate =
+ BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ WebResourceErrorBoundaryInterface.class, handler);
+ return new WebResourceErrorCompat() {
+ @Override
+ public @NetErrorCode int getErrorCode() {
+ return errorDelegate.getErrorCode();
+ }
+
+ @Override
+ @NonNull
+ public CharSequence getDescription() {
+ return errorDelegate.getDescription();
+ }
+ };
+ }
+
+ /**
+ * Conversion helper to create a WebResourceErrorCompat which delegates calls to {@param error}.
+ *
+ * @param error The WebResourceError that chromium passed in the callback.
+ */
+ @NonNull
+ @RequiresApi(23)
+ /* package */ static WebResourceErrorCompat fromWebResourceError(
+ @NonNull final WebResourceError error) {
+ return new WebResourceErrorCompat() {
+ @Override
+ public @NetErrorCode int getErrorCode() {
+ return error.getErrorCode();
+ }
+
+ @Override
+ @NonNull
+ public CharSequence getDescription() {
+ return error.getDescription();
+ }
+ };
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/WebResourceRequestCompat.java b/webkit/src/main/java/androidx/webkit/WebResourceRequestCompat.java
new file mode 100644
index 0000000..783efca
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebResourceRequestCompat.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.annotation.SuppressLint;
+import android.webkit.WebResourceRequest;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresFeature;
+import androidx.webkit.internal.WebResourceRequestAdapter;
+import androidx.webkit.internal.WebViewFeatureInternal;
+import androidx.webkit.internal.WebViewGlueCommunicator;
+
+// TODO(gsennton) add a test for this class
+
+/**
+ * Compatibility version of {@link WebResourceRequest}.
+ */
+public class WebResourceRequestCompat {
+
+ // Developers should not be able to instantiate this class.
+ private WebResourceRequestCompat() {}
+
+ /**
+ * Gets whether the request was a result of a server-side redirect.
+ *
+ * @return whether the request was a result of a server-side redirect.
+ */
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
+ public static boolean isRedirect(@NonNull WebResourceRequest request) {
+ WebViewFeatureInternal feature = WebViewFeatureInternal.WEB_RESOURCE_REQUEST_IS_REDIRECT;
+ if (feature.isSupportedByFramework()) {
+ return request.isRedirect();
+ } else if (feature.isSupportedByWebView()) {
+ return getAdapter(request).isRedirect();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ private static WebResourceRequestAdapter getAdapter(WebResourceRequest request) {
+ return WebViewGlueCommunicator.getCompatConverter().convertWebResourceRequest(request);
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
index 12d7e63..bff6170 100644
--- a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -16,27 +16,27 @@
package androidx.webkit;
-import android.os.Build;
+import android.annotation.SuppressLint;
import android.webkit.WebSettings;
+import androidx.annotation.IntDef;
+import androidx.annotation.RequiresFeature;
+import androidx.annotation.RestrictTo;
+import androidx.webkit.internal.WebSettingsAdapter;
+import androidx.webkit.internal.WebViewFeatureInternal;
+import androidx.webkit.internal.WebViewGlueCommunicator;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import androidx.annotation.IntDef;
-import androidx.annotation.RestrictTo;
-import androidx.webkit.internal.WebSettingsAdapter;
-import androidx.webkit.internal.WebViewGlueCommunicator;
-
/**
* Compatibility version of {@link android.webkit.WebSettings}
*/
public class WebSettingsCompat {
private WebSettingsCompat() {}
- // TODO(gsennton): add feature detection
-
/**
* Sets whether this WebView should raster tiles when it is
* offscreen but attached to a window. Turning this on can avoid
@@ -50,11 +50,18 @@
* visible WebViews and WebViews about to be animated to visible.
* </ul>
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.OFF_SCREEN_PRERASTER,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setOffscreenPreRaster(WebSettings webSettings, boolean enabled) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.OFF_SCREEN_PRERASTER);
+ if (webviewFeature.isSupportedByFramework()) {
webSettings.setOffscreenPreRaster(enabled);
- } else {
+ } else if (webviewFeature.isSupportedByWebView()) {
getAdapter(webSettings).setOffscreenPreRaster(enabled);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -64,11 +71,18 @@
* @return {@code true} if this WebView will raster tiles when it is
* offscreen but attached to a window.
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.OFF_SCREEN_PRERASTER,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static boolean getOffscreenPreRaster(WebSettings webSettings) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.OFF_SCREEN_PRERASTER);
+ if (webviewFeature.isSupportedByFramework()) {
return webSettings.getOffscreenPreRaster();
- } else {
+ } else if (webviewFeature.isSupportedByWebView()) {
return getAdapter(webSettings).getOffscreenPreRaster();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -86,11 +100,18 @@
*
* @param enabled Whether Safe Browsing is enabled.
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.SAFE_BROWSING_ENABLE,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setSafeBrowsingEnabled(WebSettings webSettings, boolean enabled) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.SAFE_BROWSING_ENABLE);
+ if (webviewFeature.isSupportedByFramework()) {
webSettings.setSafeBrowsingEnabled(enabled);
- } else {
+ } else if (webviewFeature.isSupportedByWebView()) {
getAdapter(webSettings).setSafeBrowsingEnabled(enabled);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -100,11 +121,18 @@
*
* @return {@code true} if Safe Browsing is enabled and {@code false} otherwise.
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.SAFE_BROWSING_ENABLE,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static boolean getSafeBrowsingEnabled(WebSettings webSettings) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.SAFE_BROWSING_ENABLE);
+ if (webviewFeature.isSupportedByFramework()) {
return webSettings.getSafeBrowsingEnabled();
- } else {
+ } else if (webviewFeature.isSupportedByWebView()) {
return getAdapter(webSettings).getSafeBrowsingEnabled();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -126,12 +154,19 @@
* Disables the action mode menu items according to {@code menuItems} flag.
* @param menuItems an integer field flag for the menu items to be disabled.
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setDisabledActionModeMenuItems(WebSettings webSettings,
@MenuItemFlags int menuItems) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS);
+ if (webviewFeature.isSupportedByFramework()) {
webSettings.setDisabledActionModeMenuItems(menuItems);
- } else {
+ } else if (webviewFeature.isSupportedByWebView()) {
getAdapter(webSettings).setDisabledActionModeMenuItems(menuItems);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -141,11 +176,18 @@
*
* @return all the disabled menu item flags combined with bitwise OR.
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static @MenuItemFlags int getDisabledActionModeMenuItems(WebSettings webSettings) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS);
+ if (webviewFeature.isSupportedByFramework()) {
return webSettings.getDisabledActionModeMenuItems();
- } else {
+ } else if (webviewFeature.isSupportedByWebView()) {
return getAdapter(webSettings).getDisabledActionModeMenuItems();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
diff --git a/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java b/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java
index 8c690f9..d354fbf 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewClientCompat.java
@@ -17,6 +17,8 @@
package androidx.webkit;
import android.os.Build;
+import android.webkit.SafeBrowsingResponse;
+import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
@@ -28,6 +30,7 @@
import androidx.annotation.RestrictTo;
import org.chromium.support_lib_boundary.WebViewClientBoundaryInterface;
+import org.chromium.support_lib_boundary.util.Features;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -41,6 +44,14 @@
// still construct a WebViewClientCompat on a pre-Lollipop devices, and explicitly invoke these
// methods, so each of these methods must also handle this case.
public class WebViewClientCompat extends WebViewClient implements WebViewClientBoundaryInterface {
+ private static final String[] sSupportedFeatures = new String[] {
+ Features.VISUAL_STATE_CALLBACK,
+ Features.RECEIVE_WEB_RESOURCE_ERROR,
+ Features.RECEIVE_HTTP_ERROR,
+ Features.SHOULD_OVERRIDE_WITH_REDIRECTS,
+ Features.SAFE_BROWSING_HIT,
+ };
+
/** @hide */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@IntDef(value = {
@@ -52,33 +63,135 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SafeBrowsingThreat {}
+ /**
+ * Returns the list of features this client supports. This feature list should always be a
+ * subset of the Features declared in WebViewFeature.
+ *
+ * @hide
+ */
+ @Override
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ public final String[] getSupportedFeatures() {
+ return sSupportedFeatures;
+ }
+
+ /**
+ * Notify the host application that {@link android.webkit.WebView} content left over from
+ * previous page navigations will no longer be drawn.
+ *
+ * <p>This callback can be used to determine the point at which it is safe to make a recycled
+ * {@link android.webkit.WebView} visible, ensuring that no stale content is shown. It is called
+ * at the earliest point at which it can be guaranteed that {@link WebView#onDraw} will no
+ * longer draw any content from previous navigations. The next draw will display either the
+ * {@link WebView#setBackgroundColor background color} of the {@link WebView}, or some of the
+ * contents of the newly loaded page.
+ *
+ * <p>This method is called when the body of the HTTP response has started loading, is reflected
+ * in the DOM, and will be visible in subsequent draws. This callback occurs early in the
+ * document loading process, and as such you should expect that linked resources (for example,
+ * CSS and images) may not be available.
+ *
+ * <p>For more fine-grained notification of visual state updates, see {@link
+ * WebViewCompat#postVisualStateCallback}.
+ *
+ * <p>Please note that all the conditions and recommendations applicable to
+ * {@link WebViewCompat#postVisualStateCallback} also apply to this API.
+ *
+ * <p>This callback is only called for main frame navigations.
+ *
+ * <p>This method is called only if {@link WebViewFeature#VISUAL_STATE_CALLBACK} is supported.
+ * You can check whether that flag is supported using {@link
+ * WebViewFeature#isFeatureSupported(String)}.
+ *
+ * @param view The {@link android.webkit.WebView} for which the navigation occurred.
+ * @param url The URL corresponding to the page navigation that triggered this callback.
+ */
@Override
public void onPageCommitVisible(@NonNull WebView view, @NonNull String url) {
}
/**
- * Invoked by chromium for the {@code onReceivedError} event. Applications are not meant to
- * override this, and should instead override the non-final {@code onReceivedError} method.
- * TODO(ntfschr): link to that method once it's implemented.
+ * Invoked by chromium (for WebView APks 67+) for the {@code onReceivedError} event.
+ * Applications are not meant to override this, and should instead override the non-final {@link
+ * onReceivedError(WebView, WebResourceRequest, WebResourceErrorCompat)} method.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Override
+ @RequiresApi(21)
public final void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request,
- /* WebResourceError */ @NonNull InvocationHandler error) {
- // TODO(ntfschr): implement this (b/73151460).
+ /* WebResourceError */ @NonNull InvocationHandler handler) {
+ onReceivedError(view, request, WebResourceErrorCompat.fromInvocationHandler(handler));
}
+ /**
+ * Invoked by chromium (in legacy WebView APKs) for the {@code onReceivedError} event on {@link
+ * Build.VERSION_CODES.M} and above. Applications are not meant to override this, and should
+ * instead override the non-final {@link onReceivedError(WebView, WebResourceRequest,
+ * WebResourceErrorCompat)} method.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ @Override
+ @RequiresApi(23)
+ public final void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request,
+ @NonNull WebResourceError error) {
+ if (Build.VERSION.SDK_INT < 23) return;
+ onReceivedError(view, request, WebResourceErrorCompat.fromWebResourceError(error));
+ }
+
+ /**
+ * Report web resource loading error to the host application. These errors usually indicate
+ * inability to connect to the server. Note that unlike the deprecated version of the callback,
+ * the new version will be called for any resource (iframe, image, etc.), not just for the main
+ * page. Thus, it is recommended to perform minimum required work in this callback.
+ *
+ * <p>This method is called only if {@link WebViewFeature#RECEIVE_WEB_RESOURCE_ERROR} is
+ * supported. You can check whether that flag is supported using {@link
+ * WebViewFeature#isFeatureSupported(String)}.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param request The originating request.
+ * @param error Information about the error occurred.
+ */
+ @SuppressWarnings("deprecation") // for invoking the old onReceivedError.
+ @RequiresApi(21)
+ public void onReceivedError(@NonNull WebView view, @NonNull WebResourceRequest request,
+ @NonNull WebResourceErrorCompat error) {
+ if (Build.VERSION.SDK_INT < 21) return;
+ if (request.isForMainFrame()) {
+ onReceivedError(view,
+ error.getErrorCode(), error.getDescription().toString(),
+ request.getUrl().toString());
+ }
+ }
+
+ /**
+ * Notify the host application that an HTTP error has been received from the server while
+ * loading a resource. HTTP errors have status codes >= 400. This callback will be called
+ * for any resource (iframe, image, etc.), not just for the main page. Thus, it is recommended
+ * to perform minimum required work in this callback. Note that the content of the server
+ * response may not be provided within the {@code errorResponse} parameter.
+ *
+ * <p>This method is called only if {@link WebViewFeature#RECEIVE_HTTP_ERROR} is supported. You
+ * can check whether that flag is supported using {@link
+ * WebViewFeature#isFeatureSupported(String)}.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param request The originating request.
+ * @param errorResponse Information about the error occurred.
+ */
@Override
public void onReceivedHttpError(@NonNull WebView view, @NonNull WebResourceRequest request,
@NonNull WebResourceResponse errorResponse) {
}
/**
- * Invoked by chromium for the {@code onSafeBrowsingHit} event. Applications are not meant to
- * override this, and should instead override the non-final {@code onSafeBrowsingHit} method.
- * TODO(ntfschr): link to that method once it's implemented.
+ * Invoked by chromium (for WebView APks 67+) for the {@code onSafeBrowsingHit} event.
+ * Applications are not meant to override this, and should instead override the non-final {@link
+ * onSafeBrowsingHit(WebView, WebResourceRequest, int, SafeBrowsingResponseCompat)} method.
*
* @hide
*/
@@ -86,14 +199,77 @@
@Override
public final void onSafeBrowsingHit(@NonNull WebView view, @NonNull WebResourceRequest request,
@SafeBrowsingThreat int threatType,
- /* SafeBrowsingResponse */ @NonNull InvocationHandler callback) {
- // TODO(ntfschr): implement this (b/73151460).
+ /* SafeBrowsingResponse */ @NonNull InvocationHandler handler) {
+ onSafeBrowsingHit(view, request, threatType,
+ SafeBrowsingResponseCompat.fromInvocationHandler(handler));
}
- // Default behavior in WebViewClient is to invoke the other (deprecated)
- // shouldOverrideUrlLoading method.
+ /**
+ * Invoked by chromium (in legacy WebView APKs) for the {@code onSafeBrowsingHit} event on
+ * {@link Build.VERSION_CODES.O_MR1} and above. Applications are not meant to override this, and
+ * should instead override the non-final {@link onSafeBrowsingHit(WebView, WebResourceRequest,
+ * int, SafeBrowsingResponseCompat)} method.
+ *
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Override
- @SuppressWarnings("deprecation")
+ @RequiresApi(27)
+ public final void onSafeBrowsingHit(@NonNull WebView view, @NonNull WebResourceRequest request,
+ @SafeBrowsingThreat int threatType, @NonNull SafeBrowsingResponse response) {
+ onSafeBrowsingHit(view, request, threatType,
+ SafeBrowsingResponseCompat.fromSafeBrowsingResponse(response));
+ }
+
+ /**
+ * Notify the host application that a loading URL has been flagged by Safe Browsing.
+ *
+ * The application must invoke the callback to indicate the preferred response. The default
+ * behavior is to show an interstitial to the user, with the reporting checkbox visible.
+ *
+ * If the application needs to show its own custom interstitial UI, the callback can be invoked
+ * asynchronously with {@link SafeBrowsingResponseCompat#backToSafety} or {@link
+ * SafeBrowsingResponseCompat#proceed}, depending on user response.
+ *
+ * @param view The WebView that hit the malicious resource.
+ * @param request Object containing the details of the request.
+ * @param threatType The reason the resource was caught by Safe Browsing, corresponding to a
+ * {@code SAFE_BROWSING_THREAT_*} value.
+ * @param callback Applications must invoke one of the callback methods.
+ */
+ public void onSafeBrowsingHit(@NonNull WebView view, @NonNull WebResourceRequest request,
+ @SafeBrowsingThreat int threatType, @NonNull SafeBrowsingResponseCompat callback) {
+ callback.showInterstitial(true);
+ }
+
+ /**
+ * Give the host application a chance to take over the control when a new
+ * url is about to be loaded in the current WebView. If WebViewClient is not
+ * provided, by default WebView will ask Activity Manager to choose the
+ * proper handler for the url. If WebViewClient is provided, return {@code true}
+ * means the host application handles the url, while return {@code false} means the
+ * current WebView handles the url.
+ *
+ * <p>Notes:
+ * <ul>
+ * <li>This method is not called for requests using the POST "method".</li>
+ * <li>This method is also called for subframes with non-http schemes, thus it is
+ * strongly disadvised to unconditionally call {@link WebView#loadUrl(String)}
+ * with the request's url from inside the method and then return {@code true},
+ * as this will make WebView to attempt loading a non-http url, and thus fail.</li>
+ * </ul>
+ *
+ * <p>This method is called only if {@link WebViewFeature#SHOULD_OVERRIDE_WITH_REDIRECTS} is
+ * supported. You can check whether that flag is supported using {@link
+ * WebViewFeature#isFeatureSupported(String)}.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param request Object containing the details of the request.
+ * @return {@code true} if the host application wants to leave the current WebView
+ * and handle the url itself, otherwise return {@code false}.
+ */
+ @Override
+ @SuppressWarnings("deprecation") // for invoking the old shouldOverrideUrlLoading.
@RequiresApi(21)
public boolean shouldOverrideUrlLoading(@NonNull WebView view,
@NonNull WebResourceRequest request) {
diff --git a/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index 88de335..bb1c4fc 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -16,6 +16,7 @@
package androidx.webkit;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -32,7 +33,7 @@
import androidx.webkit.internal.WebViewFeatureInternal;
import androidx.webkit.internal.WebViewGlueCommunicator;
import androidx.webkit.internal.WebViewProviderAdapter;
-import androidx.webkit.internal.WebViewProviderFactoryAdapter;
+import androidx.webkit.internal.WebViewProviderFactory;
import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
@@ -135,7 +136,7 @@
checkThread(webview);
getProvider(webview).insertVisualStateCallback(requestId, callback);
} else {
- WebViewFeatureInternal.throwUnsupportedOperationException("postVisualStateCallback");
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -157,12 +158,19 @@
* @param callback will be called on the UI thread with {@code true} if initialization is
* successful, {@code false} otherwise.
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.START_SAFE_BROWSING,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void startSafeBrowsing(@NonNull Context context,
@Nullable ValueCallback<Boolean> callback) {
- if (Build.VERSION.SDK_INT >= 27) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.START_SAFE_BROWSING);
+ if (webviewFeature.isSupportedByFramework()) {
WebView.startSafeBrowsing(context, callback);
- } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+ } else if (webviewFeature.isSupportedByWebView()) {
getFactory().getStatics().initSafeBrowsing(context, callback);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -189,12 +197,19 @@
* whitelist. It will be called with {@code false} if any hosts are malformed. The callback
* will be run on the UI thread
*/
+ @SuppressLint("NewApi")
+ @RequiresFeature(name = WebViewFeature.SAFE_BROWSING_WHITELIST,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static void setSafeBrowsingWhitelist(@NonNull List<String> hosts,
@Nullable ValueCallback<Boolean> callback) {
- if (Build.VERSION.SDK_INT >= 27) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.SAFE_BROWSING_WHITELIST);
+ if (webviewFeature.isSupportedByFramework()) {
WebView.setSafeBrowsingWhitelist(hosts, callback);
- } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+ } else if (webviewFeature.isSupportedByWebView()) {
getFactory().getStatics().setSafeBrowsingWhitelist(hosts, callback);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -203,12 +218,19 @@
*
* @return the url pointing to a privacy policy document which can be displayed to users.
*/
+ @SuppressLint("NewApi")
@NonNull
+ @RequiresFeature(name = WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL,
+ enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
public static Uri getSafeBrowsingPrivacyPolicyUrl() {
- if (Build.VERSION.SDK_INT >= 27) {
+ WebViewFeatureInternal webviewFeature =
+ WebViewFeatureInternal.getFeature(WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL);
+ if (webviewFeature.isSupportedByFramework()) {
return WebView.getSafeBrowsingPrivacyPolicyUrl();
- } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+ } else if (webviewFeature.isSupportedByWebView()) {
return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
}
}
@@ -258,7 +280,7 @@
private static PackageInfo getLoadedWebViewPackageInfo()
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
- Class webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
+ Class<?> webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
PackageInfo webviewPackageInfo =
(PackageInfo) webViewFactoryClass.getMethod(
"getLoadedPackageInfo").invoke(null);
@@ -274,13 +296,13 @@
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
- Class webViewFactoryClass = null;
+ Class<?> webViewFactoryClass = null;
webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
webviewPackageName = (String) webViewFactoryClass.getMethod(
"getWebViewPackageName").invoke(null);
} else {
- Class webviewUpdateServiceClass =
+ Class<?> webviewUpdateServiceClass =
Class.forName("android.webkit.WebViewUpdateService");
webviewPackageName = (String) webviewUpdateServiceClass.getMethod(
"getCurrentWebViewPackageName").invoke(null);
@@ -307,7 +329,7 @@
return new WebViewProviderAdapter(createProvider(webview));
}
- private static WebViewProviderFactoryAdapter getFactory() {
+ private static WebViewProviderFactory getFactory() {
return WebViewGlueCommunicator.getFactory();
}
@@ -322,7 +344,7 @@
throw new RuntimeException("A WebView method was called on thread '"
+ Thread.currentThread().getName() + "'. "
+ "All WebView methods must be called on the same thread. "
- + "(Expected Looper " + webview.getLooper() + " called on "
+ + "(Expected Looper " + webview.getWebViewLooper() + " called on "
+ Looper.myLooper() + ", FYI main Looper is " + Looper.getMainLooper()
+ ")");
}
diff --git a/webkit/src/main/java/androidx/webkit/WebViewFeature.java b/webkit/src/main/java/androidx/webkit/WebViewFeature.java
index d514477..5ee4c2c 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewFeature.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewFeature.java
@@ -16,6 +16,11 @@
package androidx.webkit;
+import android.content.Context;
+import android.webkit.ValueCallback;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.StringDef;
@@ -27,6 +32,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.List;
/**
* Utility class for checking which WebView Support Library features are supported on the device.
@@ -41,6 +47,23 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@StringDef(value = {
VISUAL_STATE_CALLBACK,
+ OFF_SCREEN_PRERASTER,
+ SAFE_BROWSING_ENABLE,
+ DISABLED_ACTION_MODE_MENU_ITEMS,
+ START_SAFE_BROWSING,
+ SAFE_BROWSING_WHITELIST,
+ SAFE_BROWSING_PRIVACY_POLICY_URL,
+ SERVICE_WORKER_BASIC_USAGE,
+ SERVICE_WORKER_CACHE_MODE,
+ SERVICE_WORKER_CONTENT_ACCESS,
+ SERVICE_WORKER_FILE_ACCESS,
+ SERVICE_WORKER_BLOCK_NETWORK_LOADS,
+ SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST,
+ RECEIVE_WEB_RESOURCE_ERROR,
+ RECEIVE_HTTP_ERROR,
+ SHOULD_OVERRIDE_WITH_REDIRECTS,
+ SAFE_BROWSING_HIT,
+ WEB_RESOURCE_REQUEST_IS_REDIRECT
})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@@ -50,11 +73,150 @@
* Feature for {@link #isFeatureSupported(String)}.
* This feature covers
* {@link androidx.webkit.WebViewCompat#postVisualStateCallback(android.webkit.WebView, long,
- * WebViewCompat.VisualStateCallback)}.
+ * WebViewCompat.VisualStateCallback)}, and {@link
+ * WebViewClientCompat#onPageCommitVisible(
+ * android.webkit.WebView, String)}.
*/
public static final String VISUAL_STATE_CALLBACK = Features.VISUAL_STATE_CALLBACK;
/**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link androidx.webkit.WebSettingsCompat#getOffscreenPreRaster(WebSettings)}, and
+ * {@link androidx.webkit.WebSettingsCompat#setOffscreenPreRaster(WebSettings, boolean)}.
+ */
+ public static final String OFF_SCREEN_PRERASTER = Features.OFF_SCREEN_PRERASTER;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link androidx.webkit.WebSettingsCompat#getSafeBrowsingEnabled(WebSettings)}, and
+ * {@link androidx.webkit.WebSettingsCompat#setSafeBrowsingEnabled(WebSettings, boolean)}.
+ */
+ public static final String SAFE_BROWSING_ENABLE = Features.SAFE_BROWSING_ENABLE;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link androidx.webkit.WebSettingsCompat#getDisabledActionModeMenuItems(WebSettings)}, and
+ * {@link androidx.webkit.WebSettingsCompat#setDisabledActionModeMenuItems(WebSettings, int)}.
+ */
+ public static final String DISABLED_ACTION_MODE_MENU_ITEMS =
+ Features.DISABLED_ACTION_MODE_MENU_ITEMS;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link androidx.webkit.WebViewCompat#startSafeBrowsing(Context, ValueCallback)}.
+ */
+ public static final String START_SAFE_BROWSING = Features.START_SAFE_BROWSING;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link androidx.webkit.WebViewCompat#setSafeBrowsingWhitelist(List, ValueCallback)}.
+ */
+ public static final String SAFE_BROWSING_WHITELIST = Features.SAFE_BROWSING_WHITELIST;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link WebViewCompat#getSafeBrowsingPrivacyPolicyUrl()}.
+ */
+ public static final String SAFE_BROWSING_PRIVACY_POLICY_URL =
+ Features.SAFE_BROWSING_PRIVACY_POLICY_URL;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link ServiceWorkerControllerCompat#getInstance()}.
+ */
+ public static final String SERVICE_WORKER_BASIC_USAGE = Features.SERVICE_WORKER_BASIC_USAGE;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link ServiceWorkerWebSettingsCompat#getCacheMode()}, and
+ * {@link ServiceWorkerWebSettingsCompat#setCacheMode(int)}.
+ */
+ public static final String SERVICE_WORKER_CACHE_MODE = Features.SERVICE_WORKER_CACHE_MODE;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link ServiceWorkerWebSettingsCompat#getAllowContentAccess()}, and
+ * {@link ServiceWorkerWebSettingsCompat#setAllowContentAccess(boolean)}.
+ */
+ public static final String SERVICE_WORKER_CONTENT_ACCESS =
+ Features.SERVICE_WORKER_CONTENT_ACCESS;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link ServiceWorkerWebSettingsCompat#getAllowFileAccess()}, and
+ * {@link ServiceWorkerWebSettingsCompat#setAllowFileAccess(boolean)}.
+ */
+ public static final String SERVICE_WORKER_FILE_ACCESS = Features.SERVICE_WORKER_FILE_ACCESS;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link ServiceWorkerWebSettingsCompat#getBlockNetworkLoads()}, and
+ * {@link ServiceWorkerWebSettingsCompat#setBlockNetworkLoads(boolean)}.
+ */
+ public static final String SERVICE_WORKER_BLOCK_NETWORK_LOADS =
+ Features.SERVICE_WORKER_BLOCK_NETWORK_LOADS;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link ServiceWorkerClientCompat#shouldInterceptRequest(WebResourceRequest)}.
+ */
+ public static final String SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST =
+ Features.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link WebViewClientCompat#onReceivedError(android.webkit.WebView, WebResourceRequest,
+ * WebResourceErrorCompat)}.
+ */
+ public static final String RECEIVE_WEB_RESOURCE_ERROR = Features.RECEIVE_WEB_RESOURCE_ERROR;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link WebViewClientCompat#onReceivedHttpError(android.webkit.WebView, WebResourceRequest,
+ * WebResourceResponse)}.
+ */
+ public static final String RECEIVE_HTTP_ERROR = Features.RECEIVE_HTTP_ERROR;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link WebViewClientCompat#shouldOverrideUrlLoading(android.webkit.WebView,
+ * WebResourceRequest)}.
+ */
+ public static final String SHOULD_OVERRIDE_WITH_REDIRECTS =
+ Features.SHOULD_OVERRIDE_WITH_REDIRECTS;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link WebViewClientCompat#onSafeBrowsingHit(android.webkit.WebView,
+ * WebResourceRequest, int, SafeBrowsingResponseCompat)}.
+ */
+ public static final String SAFE_BROWSING_HIT = Features.SAFE_BROWSING_HIT;
+
+ /**
+ * Feature for {@link #isFeatureSupported(String)}.
+ * This feature covers
+ * {@link WebResourceRequestCompat#isRedirect(WebResourceRequest)}.
+ */
+ public static final String WEB_RESOURCE_REQUEST_IS_REDIRECT =
+ Features.WEB_RESOURCE_REQUEST_IS_REDIRECT;
+
+ /**
* Return whether a feature is supported at run-time. This depends on the Android version of the
* device and the WebView APK on the device.
*/
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java
deleted file mode 100644
index 2e02777..0000000
--- a/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.webkit.internal;
-
-import android.os.Build;
-import android.webkit.ServiceWorkerController;
-
-import androidx.annotation.RequiresApi;
-import androidx.webkit.ServiceWorkerClientCompat;
-import androidx.webkit.ServiceWorkerControllerCompat;
-import androidx.webkit.ServiceWorkerWebSettingsCompat;
-
-/**
- * Implementation of {@link ServiceWorkerControllerCompat} meant for use on up-to-date platforms.
- * This class does not use reflection to bypass framework APIs - instead it uses android.webkit
- * APIs.
- */
-@RequiresApi(Build.VERSION_CODES.N)
-public class FrameworkServiceWorkerController extends ServiceWorkerControllerCompat {
- private final ServiceWorkerController mImpl;
- private ServiceWorkerWebSettingsCompat mSettings;
-
- public FrameworkServiceWorkerController(ServiceWorkerController impl) {
- mImpl = impl;
- }
-
- @Override
- public ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings() {
- if (mSettings == null) {
- mSettings = new FrameworksServiceWorkerWebSettings(mImpl.getServiceWorkerWebSettings());
- }
- return mSettings;
- }
-
- @Override
- public void setServiceWorkerClient(ServiceWorkerClientCompat client) {
- mImpl.setServiceWorkerClient(new FrameworkServiceWorkerClient(client));
- }
-}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java b/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java
deleted file mode 100644
index 4373756..0000000
--- a/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.webkit.internal;
-
-import android.os.Build;
-import android.webkit.ServiceWorkerWebSettings;
-
-import androidx.annotation.RequiresApi;
-import androidx.webkit.ServiceWorkerWebSettingsCompat;
-
-/**
- * Implementation of {@link ServiceWorkerWebSettingsCompat} meant for use on up-to-date platforms.
- * This class does not use reflection to bypass framework APIs - instead it uses android.webkit
- * APIs.
- */
-@RequiresApi(Build.VERSION_CODES.N)
-public class FrameworksServiceWorkerWebSettings extends ServiceWorkerWebSettingsCompat {
- private final ServiceWorkerWebSettings mImpl;
-
- public FrameworksServiceWorkerWebSettings(ServiceWorkerWebSettings impl) {
- mImpl = impl;
- }
-
- @Override
- public void setCacheMode(int mode) {
- mImpl.setCacheMode(mode);
- }
-
- @Override
- public int getCacheMode() {
- return mImpl.getCacheMode();
- }
-
- @Override
- public void setAllowContentAccess(boolean allow) {
- mImpl.setAllowContentAccess(allow);
- }
-
- @Override
- public boolean getAllowContentAccess() {
- return mImpl.getAllowContentAccess();
- }
-
- @Override
- public void setAllowFileAccess(boolean allow) {
- mImpl.setAllowContentAccess(allow);
- }
-
- @Override
- public boolean getAllowFileAccess() {
- return mImpl.getAllowFileAccess();
- }
-
- @Override
- public void setBlockNetworkLoads(boolean flag) {
- mImpl.setAllowContentAccess(flag);
- }
-
- @Override
- public boolean getBlockNetworkLoads() {
- return mImpl.getBlockNetworkLoads();
- }
-}
diff --git a/webkit/src/main/java/androidx/webkit/internal/IncompatibleApkWebViewProviderFactory.java b/webkit/src/main/java/androidx/webkit/internal/IncompatibleApkWebViewProviderFactory.java
new file mode 100644
index 0000000..71d5768
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/IncompatibleApkWebViewProviderFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.webkit.WebView;
+
+import org.chromium.support_lib_boundary.ServiceWorkerControllerBoundaryInterface;
+import org.chromium.support_lib_boundary.StaticsBoundaryInterface;
+import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
+
+/**
+ * This is a stub class used when the WebView Support Library is invoked on a device incompatible
+ * with the library (either a pre-L device or a device without a compatible WebView APK).
+ * The only method in this class that should be called is {@link #getWebViewFeatures()}.
+ */
+public class IncompatibleApkWebViewProviderFactory implements WebViewProviderFactory {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final String UNSUPPORTED_EXCEPTION_EXPLANATION =
+ "This should never happen, if this method was called it means we're trying to reach "
+ + "into WebView APK code on an incompatible device. This most likely means the current "
+ + "method is being called too early, or is being called on start-up rather than lazily";
+
+ @Override
+ public WebViewProviderBoundaryInterface createWebView(WebView webview) {
+ throw new UnsupportedOperationException(UNSUPPORTED_EXCEPTION_EXPLANATION);
+ }
+
+ @Override
+ public WebkitToCompatConverterBoundaryInterface getWebkitToCompatConverter() {
+ throw new UnsupportedOperationException(UNSUPPORTED_EXCEPTION_EXPLANATION);
+ }
+
+ @Override
+ public StaticsBoundaryInterface getStatics() {
+ throw new UnsupportedOperationException(UNSUPPORTED_EXCEPTION_EXPLANATION);
+ }
+
+ @Override
+ public String[] getWebViewFeatures() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public ServiceWorkerControllerBoundaryInterface getServiceWorkerController() {
+ throw new UnsupportedOperationException(UNSUPPORTED_EXCEPTION_EXPLANATION);
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java
index 3ffeb83..f96bbd1 100644
--- a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java
@@ -22,6 +22,7 @@
import androidx.webkit.ServiceWorkerClientCompat;
import org.chromium.support_lib_boundary.ServiceWorkerClientBoundaryInterface;
+import org.chromium.support_lib_boundary.util.Features;
/**
* Adapter between {@link ServiceWorkerClientCompat} and
@@ -39,4 +40,9 @@
public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
return mClient.shouldInterceptRequest(request);
}
+
+ @Override
+ public String[] getSupportedFeatures() {
+ return new String[] { Features.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST };
+ }
}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerAdapter.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerAdapter.java
deleted file mode 100644
index 4baa3ea..0000000
--- a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerAdapter.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.webkit.internal;
-
-import androidx.webkit.ServiceWorkerClientCompat;
-import androidx.webkit.ServiceWorkerControllerCompat;
-import androidx.webkit.ServiceWorkerWebSettingsCompat;
-
-import org.chromium.support_lib_boundary.ServiceWorkerControllerBoundaryInterface;
-import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
-import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
-
-/**
- * Adapter between {@link ServiceWorkerControllerCompat} and
- * {@link ServiceWorkerControllerBoundaryInterface} (the corresponding interface shared with the
- * support library glue in the WebView APK).
- */
-public class ServiceWorkerControllerAdapter extends ServiceWorkerControllerCompat {
- private final ServiceWorkerControllerBoundaryInterface mImpl;
- private final ServiceWorkerWebSettingsCompat mWebSettings;
-
- public ServiceWorkerControllerAdapter(ServiceWorkerControllerBoundaryInterface impl) {
- mImpl = impl;
- mWebSettings = new ServiceWorkerWebSettingsAdapter(
- BoundaryInterfaceReflectionUtil.castToSuppLibClass(
- ServiceWorkerWebSettingsBoundaryInterface.class,
- mImpl.getServiceWorkerWebSettings()));
- }
-
- @Override
- public ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings() {
- return mWebSettings;
- }
-
- @Override
- public void setServiceWorkerClient(ServiceWorkerClientCompat client) {
- mImpl.setServiceWorkerClient(BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
- new ServiceWorkerClientAdapter(client)));
- }
-}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerImpl.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerImpl.java
new file mode 100644
index 0000000..17e0a7d
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerImpl.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.annotation.SuppressLint;
+import android.webkit.ServiceWorkerController;
+
+import androidx.webkit.ServiceWorkerClientCompat;
+import androidx.webkit.ServiceWorkerControllerCompat;
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+import org.chromium.support_lib_boundary.ServiceWorkerControllerBoundaryInterface;
+import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
+import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
+
+/**
+ * Implementation of {@link ServiceWorkerControllerCompat}.
+ * This class uses either the framework, the WebView APK, or both, to implement
+ * {@link ServiceWorkerControllerCompat} functionality.
+ */
+public class ServiceWorkerControllerImpl extends ServiceWorkerControllerCompat {
+ private final ServiceWorkerController mFrameworksImpl;
+ private ServiceWorkerControllerBoundaryInterface mBoundaryInterface;
+ private final ServiceWorkerWebSettingsCompat mWebSettings;
+
+ @SuppressLint("NewApi")
+ public ServiceWorkerControllerImpl() {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_BASIC_USAGE;
+ if (feature.isSupportedByFramework()) {
+ mFrameworksImpl = ServiceWorkerController.getInstance();
+ // The current WebView APK might not be compatible with the support library, so set the
+ // boundary interface to null for now.
+ mBoundaryInterface = null;
+ mWebSettings = new ServiceWorkerWebSettingsImpl(
+ mFrameworksImpl.getServiceWorkerWebSettings(), null);
+ } else if (feature.isSupportedByWebView()) {
+ mFrameworksImpl = null;
+ mBoundaryInterface = WebViewGlueCommunicator.getFactory().getServiceWorkerController();
+ mWebSettings = new ServiceWorkerWebSettingsImpl(null,
+ BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ ServiceWorkerWebSettingsBoundaryInterface.class,
+ mBoundaryInterface.getServiceWorkerWebSettings()));
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ private ServiceWorkerControllerBoundaryInterface getBoundaryInterface() {
+ if (mBoundaryInterface != null) return mBoundaryInterface;
+
+ // If the boundary interface is null we must have a working frameworks implementation to
+ // convert into a boundary interface.
+ mBoundaryInterface = WebViewGlueCommunicator.getFactory().getServiceWorkerController();
+ return mBoundaryInterface;
+ }
+
+ @Override
+ public ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings() {
+ return mWebSettings;
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setServiceWorkerClient(ServiceWorkerClientCompat client) {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_BASIC_USAGE;
+ if (feature.isSupportedByFramework()) {
+ mFrameworksImpl.setServiceWorkerClient(new FrameworkServiceWorkerClient(client));
+ } else if (feature.isSupportedByWebView()) {
+ getBoundaryInterface().setServiceWorkerClient(
+ BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+ new ServiceWorkerClientAdapter(client)));
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsAdapter.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsAdapter.java
deleted file mode 100644
index fd49396..0000000
--- a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsAdapter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.webkit.internal;
-
-import androidx.webkit.ServiceWorkerWebSettingsCompat;
-
-import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
-
-/**
- * Adapter between {@link ServiceWorkerWebSettingsCompat} and
- * {@link ServiceWorkerWebSettingsBoundaryInterface} (the corresponding interface shared with the
- * support library glue in the WebView APK).
- */
-public class ServiceWorkerWebSettingsAdapter extends ServiceWorkerWebSettingsCompat {
- private final ServiceWorkerWebSettingsBoundaryInterface mImpl;
-
- public ServiceWorkerWebSettingsAdapter(ServiceWorkerWebSettingsBoundaryInterface impl) {
- mImpl = impl;
- }
-
- @Override
- public void setCacheMode(int mode) {
- mImpl.setCacheMode(mode);
- }
-
- @Override
- public int getCacheMode() {
- return mImpl.getCacheMode();
- }
-
- @Override
- public void setAllowContentAccess(boolean allow) {
- mImpl.setAllowContentAccess(allow);
- }
-
- @Override
- public boolean getAllowContentAccess() {
- return mImpl.getAllowContentAccess();
- }
-
- @Override
- public void setAllowFileAccess(boolean allow) {
- mImpl.setAllowFileAccess(allow);
- }
-
- @Override
- public boolean getAllowFileAccess() {
- return mImpl.getAllowFileAccess();
- }
-
- @Override
- public void setBlockNetworkLoads(boolean flag) {
- mImpl.setBlockNetworkLoads(flag);
- }
-
- @Override
- public boolean getBlockNetworkLoads() {
- return mImpl.getBlockNetworkLoads();
- }
-}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsImpl.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsImpl.java
new file mode 100644
index 0000000..9ac4450
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsImpl.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.annotation.SuppressLint;
+import android.webkit.ServiceWorkerWebSettings;
+
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
+
+/**
+ * Implementation of {@link ServiceWorkerWebSettingsCompat}.
+ * This class uses either the framework, the WebView APK, or both, to implement
+ * {@link ServiceWorkerWebSettingsCompat} functionality.
+ */
+public class ServiceWorkerWebSettingsImpl extends ServiceWorkerWebSettingsCompat {
+ private final ServiceWorkerWebSettings mFrameworksImpl;
+ private ServiceWorkerWebSettingsBoundaryInterface mBoundaryInterface;
+
+ /**
+ * This class handles three different scenarios:
+ * 1. The Android version on the device is high enough to support all APIs used.
+ * 2. The Android version on the device is too low to support any ServiceWorkerWebSettings APIs
+ * so we use the support library glue instead through
+ * {@link ServiceWorkerWebSettingsBoundaryInterface}.
+ * 3. The Android version on the device is high enough to support some ServiceWorkerWebSettings
+ * APIs, so we call into them using {@link android.webkit.ServiceWorkerWebSettings}, but the
+ * rest of the APIs are only supported by the support library glue, so whenever we call such an
+ * API we fetch a {@link ServiceWorkerWebSettingsBoundaryInterface} corresponding to our
+ * {@link android.webkit.ServiceWorkerWebSettings}.
+ */
+ public ServiceWorkerWebSettingsImpl(ServiceWorkerWebSettings frameworksImpl,
+ ServiceWorkerWebSettingsBoundaryInterface boundaryInterface) {
+ if (frameworksImpl == null && boundaryInterface == null) {
+ throw new IllegalArgumentException(
+ "Both of the possible implementations cannot be null!");
+ }
+ mFrameworksImpl = frameworksImpl;
+ mBoundaryInterface = boundaryInterface;
+ }
+
+ private ServiceWorkerWebSettingsBoundaryInterface getBoundaryInterface() {
+ if (mBoundaryInterface != null) return mBoundaryInterface;
+ // If the boundary interface is null we must have a working frameworks implementation to
+ // convert into a boundary interface.
+ mBoundaryInterface =
+ WebViewGlueCommunicator.getCompatConverter().convertServiceWorkerSettings(
+ mFrameworksImpl);
+ return mBoundaryInterface;
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setCacheMode(int mode) {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_CACHE_MODE;
+ if (feature.isSupportedByFramework()) {
+ mFrameworksImpl.setCacheMode(mode);
+ } else if (feature.isSupportedByWebView()) {
+ getBoundaryInterface().setCacheMode(mode);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public int getCacheMode() {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_CACHE_MODE;
+ if (feature.isSupportedByFramework()) {
+ return mFrameworksImpl.getCacheMode();
+ } else if (feature.isSupportedByWebView()) {
+ return getBoundaryInterface().getCacheMode();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setAllowContentAccess(boolean allow) {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_CONTENT_ACCESS;
+ if (feature.isSupportedByFramework()) {
+ mFrameworksImpl.setAllowContentAccess(allow);
+ } else if (feature.isSupportedByWebView()) {
+ getBoundaryInterface().setAllowContentAccess(allow);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public boolean getAllowContentAccess() {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_CONTENT_ACCESS;
+ if (feature.isSupportedByFramework()) {
+ return mFrameworksImpl.getAllowContentAccess();
+ } else if (feature.isSupportedByWebView()) {
+ return getBoundaryInterface().getAllowContentAccess();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setAllowFileAccess(boolean allow) {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_FILE_ACCESS;
+ if (feature.isSupportedByFramework()) {
+ mFrameworksImpl.setAllowFileAccess(allow);
+ } else if (feature.isSupportedByWebView()) {
+ getBoundaryInterface().setAllowFileAccess(allow);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public boolean getAllowFileAccess() {
+ final WebViewFeatureInternal feature = WebViewFeatureInternal.SERVICE_WORKER_FILE_ACCESS;
+ if (feature.isSupportedByFramework()) {
+ return mFrameworksImpl.getAllowFileAccess();
+ } else if (feature.isSupportedByWebView()) {
+ return getBoundaryInterface().getAllowFileAccess();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void setBlockNetworkLoads(boolean flag) {
+ final WebViewFeatureInternal feature =
+ WebViewFeatureInternal.SERVICE_WORKER_BLOCK_NETWORK_LOADS;
+ if (feature.isSupportedByFramework()) {
+ mFrameworksImpl.setBlockNetworkLoads(flag);
+ } else if (feature.isSupportedByWebView()) {
+ getBoundaryInterface().setBlockNetworkLoads(flag);
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public boolean getBlockNetworkLoads() {
+ final WebViewFeatureInternal feature =
+ WebViewFeatureInternal.SERVICE_WORKER_BLOCK_NETWORK_LOADS;
+ if (feature.isSupportedByFramework()) {
+ return mFrameworksImpl.getBlockNetworkLoads();
+ } else if (feature.isSupportedByWebView()) {
+ return getBoundaryInterface().getBlockNetworkLoads();
+ } else {
+ throw WebViewFeatureInternal.getUnsupportedOperationException();
+ }
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/SupportLibraryInfo.java b/webkit/src/main/java/androidx/webkit/internal/SupportLibraryInfo.java
deleted file mode 100644
index da8a02c..0000000
--- a/webkit/src/main/java/androidx/webkit/internal/SupportLibraryInfo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.webkit.internal;
-
-import org.chromium.support_lib_boundary.SupportLibraryInfoBoundaryInterface;
-import org.chromium.support_lib_boundary.util.Features;
-
-/**
- * Contains information about the Android Support Library part of the WebView Support Library - this
- * information is passed to the WebView APK code with the first WebView Support Library call.
- */
-public class SupportLibraryInfo implements SupportLibraryInfoBoundaryInterface {
- // Features supported by the support library itself (regardless of what the WebView APK
- // supports).
- private static final String[] SUPPORTED_FEATURES =
- new String[] {
- Features.VISUAL_STATE_CALLBACK
- };
-
- @Override
- public String[] getSupportedFeatures() {
- return SUPPORTED_FEATURES;
- }
-}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebResourceRequestAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebResourceRequestAdapter.java
new file mode 100644
index 0000000..0d6a05d
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebResourceRequestAdapter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.webkit.WebResourceRequest;
+
+import org.chromium.support_lib_boundary.WebResourceRequestBoundaryInterface;
+
+/**
+ * Adapter between {@link androidx.webkit.WebResourceRequestCompat} and
+ * {@link org.chromium.support_lib_boundary.WebResourceRequestBoundaryInterface}.
+ */
+public class WebResourceRequestAdapter {
+ private final WebResourceRequestBoundaryInterface mBoundaryInterface;
+
+ public WebResourceRequestAdapter(WebResourceRequestBoundaryInterface boundaryInterface) {
+ mBoundaryInterface = boundaryInterface;
+ }
+
+ /**
+ * Adapter method for
+ * {@link androidx.webkit.WebResourceRequestCompat#isRedirect(WebResourceRequest)}.
+ */
+ public boolean isRedirect() {
+ return mBoundaryInterface.isRedirect();
+ }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java b/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
index d16713c..07c6b5f 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
@@ -16,11 +16,21 @@
package androidx.webkit.internal;
+import android.content.Context;
import android.os.Build;
+import android.webkit.ValueCallback;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebSettings;
+import androidx.webkit.ServiceWorkerClientCompat;
+import androidx.webkit.WebResourceRequestCompat;
+import androidx.webkit.WebViewClientCompat;
+import androidx.webkit.WebViewCompat;
import androidx.webkit.WebViewFeature;
import androidx.webkit.WebViewFeature.WebViewSupportFeature;
+import java.util.List;
+
/**
* Enum representing a WebView feature, this provides functionality for determining whether a
* feature is supported by the current framework and/or WebView APK.
@@ -29,9 +39,130 @@
/**
* This feature covers
* {@link androidx.webkit.WebViewCompat#postVisualStateCallback(android.webkit.WebView, long,
- * androidx.webkit.WebViewCompat.VisualStateCallback)}.
+ * androidx.webkit.WebViewCompat.VisualStateCallback)}, and
+ * {@link WebViewClientCompat#onPageCommitVisible(android.webkit.WebView, String)}.
*/
- VISUAL_STATE_CALLBACK_FEATURE(WebViewFeature.VISUAL_STATE_CALLBACK, Build.VERSION_CODES.M);
+ VISUAL_STATE_CALLBACK_FEATURE(WebViewFeature.VISUAL_STATE_CALLBACK, Build.VERSION_CODES.M),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.WebSettingsCompat#getOffscreenPreRaster(WebSettings)}, and
+ * {@link androidx.webkit.WebSettingsCompat#setOffscreenPreRaster(WebSettings, boolean)}.
+ */
+ OFF_SCREEN_PRERASTER(WebViewFeature.OFF_SCREEN_PRERASTER, Build.VERSION_CODES.M),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.WebSettingsCompat#getSafeBrowsingEnabled(WebSettings)}, and
+ * {@link androidx.webkit.WebSettingsCompat#setSafeBrowsingEnabled(WebSettings, boolean)}.
+ */
+ SAFE_BROWSING_ENABLE(WebViewFeature.SAFE_BROWSING_ENABLE, Build.VERSION_CODES.O),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.WebSettingsCompat#getDisabledActionModeMenuItems(WebSettings)}, and
+ * {@link androidx.webkit.WebSettingsCompat#setDisabledActionModeMenuItems(WebSettings, int)}.
+ */
+ DISABLED_ACTION_MODE_MENU_ITEMS(WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS,
+ Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.WebViewCompat#startSafeBrowsing(Context, ValueCallback)}.
+ */
+ START_SAFE_BROWSING(WebViewFeature.START_SAFE_BROWSING, Build.VERSION_CODES.O_MR1),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.WebViewCompat#setSafeBrowsingWhitelist(List, ValueCallback)}.
+ */
+ SAFE_BROWSING_WHITELIST(WebViewFeature.SAFE_BROWSING_WHITELIST, Build.VERSION_CODES.O_MR1),
+
+ /**
+ * This feature covers
+ * {@link WebViewCompat#getSafeBrowsingPrivacyPolicyUrl()}.
+ */
+ SAFE_BROWSING_PRIVACY_POLICY_URL(WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL,
+ Build.VERSION_CODES.O_MR1),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.ServiceWorkerControllerCompat#getInstance()}.
+ */
+ SERVICE_WORKER_BASIC_USAGE(WebViewFeature.SERVICE_WORKER_BASIC_USAGE, Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#getCacheMode()}, and
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#setCacheMode(int)}.
+ */
+ SERVICE_WORKER_CACHE_MODE(WebViewFeature.SERVICE_WORKER_CACHE_MODE, Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#getAllowContentAccess()}, and
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#setAllowContentAccess(boolean)}.
+ */
+ SERVICE_WORKER_CONTENT_ACCESS(WebViewFeature.SERVICE_WORKER_CONTENT_ACCESS,
+ Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#getAllowFileAccess()}, and
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#setAllowFileAccess(boolean)}.
+ */
+ SERVICE_WORKER_FILE_ACCESS(WebViewFeature.SERVICE_WORKER_FILE_ACCESS, Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#getBlockNetworkLoads()}, and
+ * {@link androidx.webkit.ServiceWorkerWebSettingsCompat#setBlockNetworkLoads(boolean)}.
+ */
+ SERVICE_WORKER_BLOCK_NETWORK_LOADS(WebViewFeature.SERVICE_WORKER_BLOCK_NETWORK_LOADS,
+ Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link ServiceWorkerClientCompat#shouldInterceptRequest(WebResourceRequest)}.
+ */
+ SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST(WebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST,
+ Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link WebViewClientCompat#onReceivedError(android.webkit.WebView, WebResourceRequest,
+ * WebResourceErrorCompat)}.
+ */
+ RECEIVE_WEB_RESOURCE_ERROR(WebViewFeature.RECEIVE_WEB_RESOURCE_ERROR, Build.VERSION_CODES.M),
+
+ /**
+ * This feature covers
+ * {@link WebViewClientCompat#onReceivedHttpError(android.webkit.WebView, WebResourceRequest,
+ * WebResourceResponse)}.
+ */
+ RECEIVE_HTTP_ERROR(WebViewFeature.RECEIVE_HTTP_ERROR, Build.VERSION_CODES.M),
+
+ /**
+ * This feature covers
+ * {@link WebViewClientCompat#shouldOverrideUrlLoading(android.webkit.WebView,
+ * WebResourceRequest)}.
+ */
+ SHOULD_OVERRIDE_WITH_REDIRECTS(WebViewFeature.SHOULD_OVERRIDE_WITH_REDIRECTS,
+ Build.VERSION_CODES.N),
+
+ /**
+ * This feature covers
+ * {@link WebViewClientCompat#onSafeBrowsingHit(android.webkit.WebView,
+ * WebResourceRequest, int, SafeBrowsingResponseCompat)}.
+ */
+ SAFE_BROWSING_HIT(WebViewFeature.SAFE_BROWSING_HIT, Build.VERSION_CODES.O_MR1),
+
+ /**
+ * This feature covers
+ * {@link WebResourceRequestCompat#isRedirect(WebResourceRequest)}.
+ */
+ WEB_RESOURCE_REQUEST_IS_REDIRECT(WebViewFeature.WEB_RESOURCE_REQUEST_IS_REDIRECT,
+ Build.VERSION_CODES.N);
private final String mFeatureValue;
private final int mOsVersion;
@@ -45,12 +176,10 @@
* Return the {@link WebViewFeatureInternal} corresponding to {@param feature}.
*/
public static WebViewFeatureInternal getFeature(@WebViewSupportFeature String feature) {
- switch (feature) {
- case WebViewFeature.VISUAL_STATE_CALLBACK:
- return VISUAL_STATE_CALLBACK_FEATURE;
- default:
- throw new RuntimeException("Unknown feature " + feature);
+ for (WebViewFeatureInternal internalFeature : WebViewFeatureInternal.values()) {
+ if (internalFeature.mFeatureValue.equals(feature)) return internalFeature;
}
+ throw new RuntimeException("Unknown feature " + feature);
}
/**
@@ -77,12 +206,17 @@
WebViewGlueCommunicator.getFactory().getWebViewFeatures();
}
+
+ public static String[] getWebViewApkFeaturesForTesting() {
+ return LAZY_HOLDER.WEBVIEW_APK_FEATURES;
+ }
+
/**
* Utility method for throwing an exception explaining that the feature the app trying to use
* isn't supported.
*/
- public static void throwUnsupportedOperationException(String feature) {
- throw new UnsupportedOperationException("Feature " + feature
- + " is not supported by the current version of the framework and WebView APK");
+ public static UnsupportedOperationException getUnsupportedOperationException() {
+ return new UnsupportedOperationException("This method is not supported by the current "
+ + "version of the framework and the current WebView APK");
}
}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
index 33ac145..9adffe7 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
@@ -39,49 +39,53 @@
/**
* Fetch the one global support library WebViewProviderFactory from the WebView glue layer.
*/
- public static WebViewProviderFactoryAdapter getFactory() {
+ public static WebViewProviderFactory getFactory() {
return LAZY_FACTORY_HOLDER.INSTANCE;
}
public static WebkitToCompatConverter getCompatConverter() {
- return LAZY_FACTORY_HOLDER.COMPAT_CONVERTER;
+ return LAZY_COMPAT_CONVERTER_HOLDER.INSTANCE;
}
private static class LAZY_FACTORY_HOLDER {
- static final WebViewProviderFactoryAdapter INSTANCE =
- new WebViewProviderFactoryAdapter(
- WebViewGlueCommunicator.createGlueProviderFactory());
- static final WebkitToCompatConverter COMPAT_CONVERTER =
- new WebkitToCompatConverter(
- INSTANCE.getWebkitToCompatConverter());
+ private static final WebViewProviderFactory INSTANCE =
+ WebViewGlueCommunicator.createGlueProviderFactory();
}
- private static InvocationHandler fetchGlueProviderFactoryImpl() {
+ private static class LAZY_COMPAT_CONVERTER_HOLDER {
+ static final WebkitToCompatConverter INSTANCE = new WebkitToCompatConverter(
+ WebViewGlueCommunicator.getFactory().getWebkitToCompatConverter());
+ }
+
+ private static InvocationHandler fetchGlueProviderFactoryImpl() throws IllegalAccessException,
+ InvocationTargetException, ClassNotFoundException, NoSuchMethodException {
+ Class<?> glueFactoryProviderFetcherClass = Class.forName(
+ GLUE_FACTORY_PROVIDER_FETCHER_CLASS, false, getWebViewClassLoader());
+ Method createProviderFactoryMethod = glueFactoryProviderFetcherClass.getDeclaredMethod(
+ GLUE_FACTORY_PROVIDER_FETCHER_METHOD);
+ return (InvocationHandler) createProviderFactoryMethod.invoke(null);
+ }
+
+ private static WebViewProviderFactory createGlueProviderFactory() {
+ InvocationHandler invocationHandler;
try {
- Class<?> glueFactoryProviderFetcherClass = Class.forName(
- GLUE_FACTORY_PROVIDER_FETCHER_CLASS, false, getWebViewClassLoader());
- Method createProviderFactoryMethod = glueFactoryProviderFetcherClass.getDeclaredMethod(
- GLUE_FACTORY_PROVIDER_FETCHER_METHOD, InvocationHandler.class);
- return (InvocationHandler) createProviderFactoryMethod.invoke(null,
- BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
- new SupportLibraryInfo()));
+ invocationHandler = fetchGlueProviderFactoryImpl();
+ // The only way we should fail to fetch the provider-factory is if the class we are
+ // calling into doesn't exist - any other kind of failure is unexpected and should cause
+ // a run-time exception.
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
- throw new RuntimeException(e);
+ // If WebView APK support library glue entry point doesn't exist then return a Provider
+ // factory that declares that there are no features available.
+ return new IncompatibleApkWebViewProviderFactory();
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
- // TODO(gsennton) if the above happens we should avoid throwing an exception! And probably
- // declare that the list of features supported by the WebView APK is empty.
- }
-
- private static WebViewProviderFactoryBoundaryInterface createGlueProviderFactory() {
- InvocationHandler invocationHandler = fetchGlueProviderFactoryImpl();
- return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
- WebViewProviderFactoryBoundaryInterface.class, invocationHandler);
+ return new WebViewProviderFactoryAdapter(BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ WebViewProviderFactoryBoundaryInterface.class, invocationHandler));
}
/**
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactory.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactory.java
new file mode 100644
index 0000000..5e4669a
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.webkit.WebView;
+
+import org.chromium.support_lib_boundary.ServiceWorkerControllerBoundaryInterface;
+import org.chromium.support_lib_boundary.StaticsBoundaryInterface;
+import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
+
+/**
+ * Interface representing {@link android.webkit.WebViewProviderFactory}.
+ * On device with a compatible WebView APK this interface is implemented by a class defined in the
+ * WebView APK itself.
+ * On devices without a compatible WebView APK this interface is implemented by a stub class
+ * {@link androidx.webkit.internal.IncompatibleWebViewProviderFactory}.
+ */
+public interface WebViewProviderFactory {
+ /**
+ * Create a support library version of {@link android.webkit.WebViewProvider}.
+ */
+ WebViewProviderBoundaryInterface createWebView(WebView webview);
+
+ /**
+ * Create the boundary interface for {@link androidx.webkit.internal.WebkitToCompatConverter}
+ * which converts android.webkit classes into their corresponding support library classes.
+ */
+ WebkitToCompatConverterBoundaryInterface getWebkitToCompatConverter();
+
+ /**
+ * Fetch the boundary interface representing
+ * {@link android.webkit.WebViewFactoryProvider#Statics}.
+ */
+ StaticsBoundaryInterface getStatics();
+
+ /**
+ * Fetch the features supported by the current WebView APK.
+ */
+ String[] getWebViewFeatures();
+
+ /**
+ * Fetch the boundary interface representing {@link android.webkit.ServiceWorkerController}.
+ */
+ ServiceWorkerControllerBoundaryInterface getServiceWorkerController();
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
index efe0e64..43e5eae 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
@@ -29,7 +29,7 @@
* Adapter for WebViewProviderFactoryBoundaryInterface providing static WebView functionality
* similar to that provided by {@link android.webkit.WebViewFactoryProvider}.
*/
-public class WebViewProviderFactoryAdapter {
+public class WebViewProviderFactoryAdapter implements WebViewProviderFactory {
WebViewProviderFactoryBoundaryInterface mImpl;
public WebViewProviderFactoryAdapter(WebViewProviderFactoryBoundaryInterface impl) {
@@ -41,6 +41,7 @@
* {@link android.webkit.WebViewProvider} - the class used to implement
* {@link androidx.webkit.WebViewCompat}.
*/
+ @Override
public WebViewProviderBoundaryInterface createWebView(WebView webview) {
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
WebViewProviderBoundaryInterface.class, mImpl.createWebView(webview));
@@ -51,6 +52,7 @@
* {@link androidx.webkit.internal.WebkitToCompatConverter}, which converts android.webkit
* classes into their corresponding support library classes.
*/
+ @Override
public WebkitToCompatConverterBoundaryInterface getWebkitToCompatConverter() {
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
WebkitToCompatConverterBoundaryInterface.class, mImpl.getWebkitToCompatConverter());
@@ -60,6 +62,7 @@
* Adapter method for fetching the support library class representing
* {@link android.webkit.WebViewFactoryProvider#Statics}.
*/
+ @Override
public StaticsBoundaryInterface getStatics() {
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
StaticsBoundaryInterface.class, mImpl.getStatics());
@@ -68,6 +71,7 @@
/**
* Adapter method for fetching the features supported by the current WebView APK.
*/
+ @Override
public String[] getWebViewFeatures() {
return mImpl.getSupportedFeatures();
}
@@ -76,6 +80,7 @@
* Adapter method for fetching the support library class representing
* {@link android.webkit.ServiceWorkerController}.
*/
+ @Override
public ServiceWorkerControllerBoundaryInterface getServiceWorkerController() {
return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
ServiceWorkerControllerBoundaryInterface.class, mImpl.getServiceWorkerController());
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
index a07cf07..e333480 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
@@ -16,8 +16,12 @@
package androidx.webkit.internal;
+import android.webkit.ServiceWorkerWebSettings;
+import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
+import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
+import org.chromium.support_lib_boundary.WebResourceRequestBoundaryInterface;
import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
@@ -42,4 +46,26 @@
return new WebSettingsAdapter(BoundaryInterfaceReflectionUtil.castToSuppLibClass(
WebSettingsBoundaryInterface.class, mImpl.convertSettings(webSettings)));
}
+
+ /**
+ * Return a {@link ServiceWorkerWebSettingsBoundaryInterface} linked to the given
+ * {@link ServiceWorkerWebSettings }such that calls on either of those objects affect the other
+ * object.
+ */
+ public ServiceWorkerWebSettingsBoundaryInterface convertServiceWorkerSettings(
+ ServiceWorkerWebSettings settings) {
+ return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ ServiceWorkerWebSettingsBoundaryInterface.class,
+ mImpl.convertServiceWorkerSettings(settings));
+ }
+
+ /**
+ * Return a {@link WebResourceRequestAdapter} linked to the given {@link WebResourceRequest} so
+ * that calls on either of those objects affect the other object.
+ */
+ public WebResourceRequestAdapter convertWebResourceRequest(WebResourceRequest request) {
+ return new WebResourceRequestAdapter(BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+ WebResourceRequestBoundaryInterface.class,
+ mImpl.convertWebResourceRequest(request)));
+ }
}