am 33c086b1: Merge "Fix SubMenu in NavigationView" into lmp-mr1-ub-dev
* commit '33c086b170ad408746728df4a4b5d6d9f10e7508':
Fix SubMenu in NavigationView
diff --git a/.gitignore b/.gitignore
index eee06e7..c8c3ed8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,8 @@
+.classpath
.gradle
.idea/
+.project
+.settings/
+project.properties
+**/bin
+**/gen
diff --git a/build.gradle b/build.gradle
index 5d8a0cb..fb4083b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,8 +9,8 @@
}
}
-ext.supportVersion = '22.2.0'
-ext.extraVersion = 14
+ext.supportVersion = '23.0.0-rc1'
+ext.extraVersion = 15
ext.supportRepoOut = ''
ext.buildToolsVersion = '22.1.0'
ext.buildNumber = Integer.toString(ext.extraVersion)
@@ -166,7 +166,6 @@
project.plugins.whenPluginAdded { plugin ->
if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
project.android.buildToolsVersion = rootProject.buildToolsVersion
- project.android.aaptOptions.useNewCruncher = false
}
}
}
diff --git a/design/build.gradle b/design/build.gradle
index ca8018c..3517cfc 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -13,7 +13,7 @@
sourceSets {
main.manifest.srcFile 'AndroidManifest.xml'
main.java.srcDirs = ['base', 'eclair-mr1', 'honeycomb', 'honeycomb-mr1', 'lollipop', 'src']
- main.res.srcDir 'res'
+ main.res.srcDirs 'res', 'res-public'
main.assets.srcDir 'assets'
main.resources.srcDir 'src'
diff --git a/design/res-public/values/public_attrs.xml b/design/res-public/values/public_attrs.xml
new file mode 100644
index 0000000..737596b
--- /dev/null
+++ b/design/res-public/values/public_attrs.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Definitions of attributes to be exposed as public -->
+<resources>
+ <public type="attr" name="backgroundTint"/>
+ <public type="attr" name="backgroundTintMode"/>
+ <public type="attr" name="borderWidth"/>
+ <public type="attr" name="collapsedTitleTextAppearance"/>
+ <public type="attr" name="contentScrim"/>
+ <public type="attr" name="elevation"/>
+ <public type="attr" name="errorEnabled"/>
+ <public type="attr" name="errorTextAppearance"/>
+ <public type="attr" name="expandedTitleMargin"/>
+ <public type="attr" name="expandedTitleMarginBottom"/>
+ <public type="attr" name="expandedTitleMarginEnd"/>
+ <public type="attr" name="expandedTitleMarginStart"/>
+ <public type="attr" name="expandedTitleMarginTop"/>
+ <public type="attr" name="expandedTitleTextAppearance"/>
+ <public type="attr" name="fabSize"/>
+ <public type="attr" name="headerLayout"/>
+ <public type="attr" name="hintTextAppearance"/>
+ <public type="attr" name="itemBackground"/>
+ <public type="attr" name="itemIconTint"/>
+ <public type="attr" name="itemTextColor"/>
+ <public type="attr" name="keylines"/>
+ <public type="attr" name="menu"/>
+ <public type="attr" name="pressedTranslationZ"/>
+ <public type="attr" name="rippleColor"/>
+ <public type="attr" name="statusBarBackground"/>
+ <public type="attr" name="statusBarScrim"/>
+ <public type="attr" name="tabBackground"/>
+ <public type="attr" name="tabContentStart"/>
+ <public type="attr" name="tabGravity"/>
+ <public type="attr" name="tabIndicatorColor"/>
+ <public type="attr" name="tabIndicatorHeight"/>
+ <public type="attr" name="tabMaxWidth"/>
+ <public type="attr" name="tabMinWidth"/>
+ <public type="attr" name="tabMode"/>
+ <public type="attr" name="tabPadding"/>
+ <public type="attr" name="tabPaddingBottom"/>
+ <public type="attr" name="tabPaddingEnd"/>
+ <public type="attr" name="tabPaddingStart"/>
+ <public type="attr" name="tabPaddingTop"/>
+ <public type="attr" name="tabSelectedTextColor"/>
+ <public type="attr" name="tabTextAppearance"/>
+ <public type="attr" name="tabTextColor"/>
+ <public type="attr" name="toolbarId"/>
+</resources>
diff --git a/design/res-public/values/public_styles.xml b/design/res-public/values/public_styles.xml
new file mode 100644
index 0000000..f65e5e3
--- /dev/null
+++ b/design/res-public/values/public_styles.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Definitions of styles to be exposed as public -->
+<resources>
+ <public type="style" name="TextAppearance.Design.Error"/>
+ <public type="style" name="TextAppearance.Design.Hint"/>
+ <public type="style" name="TextAppearance.Design.Tab"/>
+ <public type="style" name="Widget.Design.AppBarLayout"/>
+ <public type="style" name="Widget.Design.CollapsingToolbar"/>
+ <public type="style" name="Widget.Design.CoordinatorLayout"/>
+ <public type="style" name="Widget.Design.FloatingActionButton"/>
+ <public type="style" name="Widget.Design.NavigationView"/>
+ <public type="style" name="Widget.Design.Snackbar"/>
+ <public type="style" name="Widget.Design.TabLayout"/>
+ <public type="style" name="Widget.Design.TextInputLayout"/>
+</resources>
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 8675e6d..c3d0ff2 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -490,6 +490,7 @@
final Class<Behavior> clazz = (Class<Behavior>) Class.forName(fullName, true,
context.getClassLoader());
c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
+ c.setAccessible(true);
constructors.put(fullName, c);
}
return c.newInstance(context, attrs);
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 2efee17..9234de8 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -24,6 +24,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;
import android.support.design.R;
import android.support.v4.view.ViewCompat;
@@ -162,7 +163,7 @@
*
* @param color ARGB color to use for the ripple.
*/
- public void setRippleColor(int color) {
+ public void setRippleColor(@ColorInt int color) {
if (mRippleColor != color) {
mRippleColor = color;
mImpl.setRippleColor(color);
diff --git a/graphics/Android.mk b/graphics/Android.mk
new file mode 100644
index 0000000..365b3b1
--- /dev/null
+++ b/graphics/Android.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
new file mode 100644
index 0000000..63e93b7
--- /dev/null
+++ b/graphics/drawable/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+#static vector drawable library
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v7-vectordrawable
+LOCAL_SDK_VERSION := 7
+LOCAL_SRC_FILES := $(call all-java-files-under, static)
+
+LOCAL_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#Animated vector drawable library
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v11-animatedvectordrawable
+LOCAL_SDK_VERSION := 11
+LOCAL_SRC_FILES := $(call all-java-files-under, animated)
+
+LOCAL_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/graphics/drawable/AndroidManifest.xml b/graphics/drawable/AndroidManifest.xml
new file mode 100644
index 0000000..83124c7
--- /dev/null
+++ b/graphics/drawable/AndroidManifest.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.support.graphics.drawable">
+ <application />
+</manifest>
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
new file mode 100644
index 0000000..78ef62d
--- /dev/null
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.support.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.DrawableRes;
+import android.support.v4.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * This class uses {@link android.animation.ObjectAnimator} and
+ * {@link android.animation.AnimatorSet} to animate the properties of a
+ * {@link android.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
+ * <p>
+ * AnimatedVectorDrawableCompat are normally defined as 3 separate XML files.
+ * </p>
+ * <p>
+ * First is the XML file for {@link android.graphics.drawable.VectorDrawableCompat}. Note that we
+ * allow the animation to happen on the group's attributes and path's attributes, which requires they
+ * are uniquely named in this XML file. Groups and paths without animations do not need names.
+ * </p>
+ * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
+ * <pre>
+ * <vector xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:height="64dp"
+ * android:width="64dp"
+ * android:viewportHeight="600"
+ * android:viewportWidth="600" >
+ * <group
+ * android:name="rotationGroup"
+ * android:pivotX="300.0"
+ * android:pivotY="300.0"
+ * android:rotation="45.0" >
+ * <path
+ * android:name="v"
+ * android:fillColor="#000000"
+ * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+ * </group>
+ * </vector>
+ * </pre></li>
+ * <p>
+ * Second is the AnimatedVectorDrawableCompat's XML file, which defines the target
+ * VectorDrawableCompat, the target paths and groups to animate, the properties of the path and
+ * group to animate and the animations defined as the ObjectAnimators or AnimatorSets.
+ * </p>
+ * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file.
+ * Note how we use the names to refer to the groups and paths in the vectordrawable.xml.
+ * <pre>
+ * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:drawable="@drawable/vectordrawable" >
+ * <target
+ * android:name="rotationGroup"
+ * android:animation="@anim/rotation" />
+ * <target
+ * android:name="v"
+ * android:animation="@anim/path_morph" />
+ * </animated-vector>
+ * </pre></li>
+ * <p>
+ * Last is the Animator XML file, which is the same as a normal ObjectAnimator or AnimatorSet. To
+ * complete this example, here are the 2 animator files used in avd.xml: rotation.xml and
+ * path_morph.xml.
+ * </p>
+ * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees.
+ * <pre>
+ * <objectAnimator
+ * android:duration="6000"
+ * android:propertyName="rotation"
+ * android:valueFrom="0"
+ * android:valueTo="360" />
+ * </pre></li>
+ * <li>Here is the path_morph.xml, which will morph the path from one shape to
+ * the other. Note that the paths must be compatible for morphing.
+ * In more details, the paths should have exact same length of commands, and
+ * exact same length of parameters for each commands.
+ * Note that the path strings are better stored in strings.xml for reusing.
+ * <pre>
+ * <set xmlns:android="http://schemas.android.com/apk/res/android">
+ * <objectAnimator
+ * android:duration="3000"
+ * android:propertyName="pathData"
+ * android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z"
+ * android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z"
+ * android:valueType="pathType"/>
+ * </set>
+ * </pre></li>
+ *
+ * @attr ref android.R.styleable#AnimatedVectorDrawableCompat_drawable
+ * @attr ref android.R.styleable#AnimatedVectorDrawableCompatTarget_name
+ * @attr ref android.R.styleable#AnimatedVectorDrawableCompatTarget_animation
+ */
+public class AnimatedVectorDrawableCompat extends Drawable implements Animatable {
+ private static final String LOGTAG = "AnimatedVectorDrawableCompat";
+
+ private static final String ANIMATED_VECTOR = "animated-vector";
+ private static final String TARGET = "target";
+
+ private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+
+ private AnimatedVectorDrawableCompatState mAnimatedVectorState;
+
+ private boolean mMutated;
+
+ private Context mContext;
+
+ // Currently the only useful ctor.
+ public AnimatedVectorDrawableCompat(Context context) {
+ this(context, null, null);
+ }
+
+ private AnimatedVectorDrawableCompat(Context context, AnimatedVectorDrawableCompatState state,
+ Resources res) {
+ mContext = context;
+ if (state != null) {
+ mAnimatedVectorState = state;
+ } else {
+ mAnimatedVectorState = new AnimatedVectorDrawableCompatState(context, state, mCallback,
+ res);
+ }
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mAnimatedVectorState =
+ new AnimatedVectorDrawableCompatState(null, mAnimatedVectorState, mCallback,
+ null);
+ mMutated = true;
+ }
+ return this;
+ }
+
+
+ /**
+ * Create a AnimatedVectorDrawableCompat object.
+ *
+ * @param context the context for creating the animators.
+ * @param resId the resource ID for AnimatedVectorDrawableCompat object.
+ * @return a new AnimatedVectorDrawableCompat or null if parsing error is found.
+ */
+ @Nullable
+ public static AnimatedVectorDrawableCompat create(@NonNull Context context,
+ @DrawableRes int resId) {
+ Resources resources = context.getResources();
+ try {
+ final XmlPullParser parser = resources.getXml(resId);
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ final AnimatedVectorDrawableCompat drawable = new AnimatedVectorDrawableCompat(context);
+ drawable.inflate(resources, parser, attrs, context.getTheme());
+
+ return drawable;
+ } catch (XmlPullParserException e) {
+ Log.e(LOGTAG, "parser error", e);
+ } catch (IOException e) {
+ Log.e(LOGTAG, "parser error", e);
+ }
+ return null;
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations();
+ return mAnimatedVectorState;
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return super.getChangingConfigurations() | mAnimatedVectorState.mChangingConfigurations;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mAnimatedVectorState.mVectorDrawable.draw(canvas);
+ if (isStarted()) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mAnimatedVectorState.mVectorDrawable.setBounds(bounds);
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ return mAnimatedVectorState.mVectorDrawable.setState(state);
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ return mAnimatedVectorState.mVectorDrawable.setLevel(level);
+ }
+
+ // @Override
+ public int getAlpha() {
+ return mAnimatedVectorState.mVectorDrawable.getAlpha();
+ }
+
+ // @Override
+ public void setAlpha(int alpha) {
+ mAnimatedVectorState.mVectorDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter);
+ }
+
+ public void setTintList(ColorStateList tint) {
+ mAnimatedVectorState.mVectorDrawable.setTintList(tint);
+ }
+
+ public void setTintMode(Mode tintMode) {
+ mAnimatedVectorState.mVectorDrawable.setTintMode(tintMode);
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ mAnimatedVectorState.mVectorDrawable.setVisible(visible, restart);
+ return super.setVisible(visible, restart);
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mAnimatedVectorState.mVectorDrawable.isStateful();
+ }
+
+ @Override
+ public int getOpacity() {
+ return mAnimatedVectorState.mVectorDrawable.getOpacity();
+ }
+
+ public int getIntrinsicWidth() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth();
+ }
+
+ public int getIntrinsicHeight() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight();
+ }
+
+ /**
+ * Obtains styled attributes from the theme, if available, or unstyled
+ * resources if the theme is null.
+ */
+ static TypedArray obtainAttributes(
+ Resources res, Theme theme, AttributeSet set, int[] attrs) {
+ if (theme == null) {
+ return res.obtainAttributes(set, attrs);
+ }
+ return theme.obtainStyledAttributes(set, attrs, 0, 0);
+ }
+
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+ int eventType = parser.getEventType();
+ float pathErrorScale = 1;
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = parser.getName();
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "tagName is " + tagName);
+ }
+ if (ANIMATED_VECTOR.equals(tagName)) {
+ final TypedArray a =
+ obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawable);
+
+ int drawableRes = a.getResourceId(R.styleable.AnimatedVectorDrawable_drawable,
+ 0);
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "drawableRes is " + drawableRes);
+ }
+ if (drawableRes != 0) {
+ VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(res,
+ drawableRes, theme);
+ vectorDrawable.setAllowCaching(false);
+ vectorDrawable.setCallback(mCallback);
+ pathErrorScale = vectorDrawable.getPixelSize();
+ if (mAnimatedVectorState.mVectorDrawable != null) {
+ mAnimatedVectorState.mVectorDrawable.setCallback(null);
+ }
+ mAnimatedVectorState.mVectorDrawable = vectorDrawable;
+ }
+ a.recycle();
+ } else if (TARGET.equals(tagName)) {
+ final TypedArray a =
+ res.obtainAttributes(attrs, R.styleable.AnimatedVectorDrawableTarget);
+ final String target = a.getString(
+ R.styleable.AnimatedVectorDrawableTarget_name);
+
+ int id = a.getResourceId(R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+ if (id != 0) {
+ Animator objectAnimator = AnimatorInflater.loadAnimator(mContext, id);
+ setupAnimatorsForTarget(target, objectAnimator);
+ }
+ a.recycle();
+ }
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ @Override
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ inflate(res, parser, attrs, null);
+ }
+
+ public boolean canApplyTheme() {
+ return false;
+ }
+
+ private static class AnimatedVectorDrawableCompatState extends ConstantState {
+ int mChangingConfigurations;
+ VectorDrawableCompat mVectorDrawable;
+ ArrayList<Animator> mAnimators;
+ ArrayMap<Animator, String> mTargetNameMap;
+ Context mContext;
+
+ public AnimatedVectorDrawableCompatState(Context context,
+ AnimatedVectorDrawableCompatState copy, Callback owner, Resources res) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ if (copy.mVectorDrawable != null) {
+ final ConstantState cs = copy.mVectorDrawable.getConstantState();
+ if (res != null) {
+ mVectorDrawable = (VectorDrawableCompat) cs.newDrawable(res);
+ } else {
+ mVectorDrawable = (VectorDrawableCompat) cs.newDrawable();
+ }
+ mVectorDrawable = (VectorDrawableCompat) mVectorDrawable.mutate();
+ mVectorDrawable.setCallback(owner);
+ mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
+ mVectorDrawable.setAllowCaching(false);
+ }
+ if (copy.mAnimators != null) {
+ final int numAnimators = copy.mAnimators.size();
+ mAnimators = new ArrayList<Animator>(numAnimators);
+ mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
+ for (int i = 0; i < numAnimators; ++i) {
+ Animator anim = copy.mAnimators.get(i);
+ Animator animClone = anim.clone();
+ String targetName = copy.mTargetNameMap.get(anim);
+ Object targetObject = mVectorDrawable.getTargetByName(targetName);
+ animClone.setTarget(targetObject);
+ mAnimators.add(animClone);
+ mTargetNameMap.put(animClone, targetName);
+ }
+ }
+ }
+
+ if (context != null) {
+ mContext = context;
+ } else {
+ mContext = copy.mContext;
+ }
+
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new AnimatedVectorDrawableCompat(mContext, this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedVectorDrawableCompat(mContext, this, res);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ private void setupAnimatorsForTarget(String name, Animator animator) {
+ Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
+ animator.setTarget(target);
+ if (mAnimatedVectorState.mAnimators == null) {
+ mAnimatedVectorState.mAnimators = new ArrayList<Animator>();
+ mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
+ }
+ mAnimatedVectorState.mAnimators.add(animator);
+ mAnimatedVectorState.mTargetNameMap.put(animator, name);
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "add animator for target " + name + " " + animator);
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ if (animator.isRunning()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isStarted() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ if (animators == null) {
+ return false;
+ }
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ if (animator.isRunning()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void start() {
+ // If any one of the animator has not ended, do nothing.
+ if (isStarted()) {
+ return;
+ }
+ // Otherwise, kick off every animator.
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ animator.start();
+ }
+ invalidateSelf();
+ }
+
+ @Override
+ public void stop() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ animator.end();
+ }
+ }
+
+ private final Callback mCallback = new Callback() {
+ @Override
+ public void invalidateDrawable(Drawable who) {
+ invalidateSelf();
+ }
+
+ @Override
+ public void scheduleDrawable(Drawable who, Runnable what, long when) {
+ scheduleSelf(what, when);
+ }
+
+ @Override
+ public void unscheduleDrawable(Drawable who, Runnable what) {
+ unscheduleSelf(what);
+ }
+ };
+}
diff --git a/graphics/drawable/res/values/attrs.xml b/graphics/drawable/res/values/attrs.xml
new file mode 100644
index 0000000..b54c9a6
--- /dev/null
+++ b/graphics/drawable/res/values/attrs.xml
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+ no tint is applied. May be a color state list. -->
+ <attr name="tint" format="color" />
+ <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+ default value is src_in, which treats the drawable as an alpha mask. -->
+ <attr name="tintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+ <!-- Animation to use on each child. -->
+ <attr name="animation" format="reference" />
+ <!-- alpha property of the view, as a value between 0 (completely transparent) and 1
+ (completely opaque). -->
+ <attr name="alpha" format="float" />
+ <attr name="pivotX" format="float|fraction" />
+ <attr name="pivotY" format="float|fraction" />
+ <!-- rotation of the view, in degrees. -->
+ <attr name="rotation" format="float" />
+
+ <!-- scale of the view in the x direction. -->
+ <attr name="scaleX" format="float" />
+
+ <!-- scale of the view in the y direction. -->
+ <attr name="scaleY" format="float" />
+ <!-- Makes the TextView be exactly this many pixels tall.
+ You could get the same effect by specifying this number in the
+ layout parameters. -->
+ <attr name="height" format="dimension" />
+ <!-- Makes the TextView be exactly this many pixels wide.
+ You could get the same effect by specifying this number in the
+ layout parameters. -->
+ <attr name="width" format="dimension" />
+ <!-- A unique name for the given item. This must use a Java-style naming
+ convention to ensure the name is unique, for example
+ "com.mycompany.MyName". -->
+ <attr name="name" format="string" />
+
+ <!-- ========================== -->
+ <!-- VectorDrawable class -->
+ <!-- ========================== -->
+ <eat-comment />
+
+ <!-- Drawable used to draw vector paths. -->
+ <declare-styleable name="VectorDrawable">
+ <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+ no tint is applied. May be a color state list. -->
+ <attr name="tint" />
+ <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+ default value is src_in, which treats the drawable as an alpha mask. -->
+ <attr name="tintMode" />
+ <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+ RTL (right-to-left). -->
+ <attr name="autoMirrored" format="boolean" />
+ <!-- The intrinsic width of the Vector Drawable. -->
+ <attr name="width" />
+ <!-- The intrinsic height of the Vector Drawable. -->
+ <attr name="height" />
+ <!-- The width of the canvas the drawing is on. -->
+ <attr name="viewportWidth" format="float"/>
+ <!-- The height of the canvas the drawing is on. -->
+ <attr name="viewportHeight" format="float"/>
+ <!-- The name of this vector drawable -->
+ <attr name="name" />
+ <!-- The opacity of the whole vector drawable, as a value between 0
+ (completely transparent) and 1 (completely opaque). -->
+ <attr name="alpha" />
+ </declare-styleable>
+
+ <!-- Defines the group used in VectorDrawables. -->
+ <declare-styleable name="VectorDrawableGroup">
+ <!-- The name of this group -->
+ <attr name="name" />
+ <!-- The amount to rotate the group -->
+ <attr name="rotation" />
+ <!-- The X coordinate of the center of rotation of a group -->
+ <attr name="pivotX" />
+ <!-- The Y coordinate of the center of rotation of a group -->
+ <attr name="pivotY" />
+ <!-- The amount to translate the group on X coordinate -->
+ <attr name="translateX" format="float"/>
+ <!-- The amount to translate the group on Y coordinate -->
+ <attr name="translateY" format="float"/>
+ <!-- The amount to scale the group on X coordinate -->
+ <attr name="scaleX" />
+ <!-- The amount to scale the group on X coordinate -->
+ <attr name="scaleY" />
+ </declare-styleable>
+
+ <!-- Defines the path used in VectorDrawables. -->
+ <declare-styleable name="VectorDrawablePath">
+ <!-- The name of this path -->
+ <attr name="name" />
+ <!-- The width a path stroke -->
+ <attr name="strokeWidth" format="float" />
+ <!-- The color to stroke the path if not defined implies no stroke-->
+ <attr name="strokeColor" format="color" />
+ <!-- The opacity of a path stroke, as a value between 0 (completely transparent)
+ and 1 (completely opaque) -->
+ <attr name="strokeAlpha" format="float" />
+ <!-- The color to fill the path if not defined implies no fill-->
+ <attr name="fillColor" format="color" />
+ <!-- The alpha of the path fill, as a value between 0 (completely transparent)
+ and 1 (completely opaque)-->
+ <attr name="fillAlpha" format="float" />
+ <!-- The specification of the operations that define the path -->
+ <attr name="pathData" format="string" />
+ <!-- The fraction of the path to trim from the start from 0 to 1 -->
+ <attr name="trimPathStart" format="float" />
+ <!-- The fraction of the path to trim from the end from 0 to 1 -->
+ <attr name="trimPathEnd" format="float" />
+ <!-- Shift trim region (allows visible region to include the start and end) from 0 to 1 -->
+ <attr name="trimPathOffset" format="float" />
+ <!-- The linecap for a stroked path -->
+ <attr name="strokeLineCap" format="enum">
+ <enum name="butt" value="0"/>
+ <enum name="round" value="1"/>
+ <enum name="square" value="2"/>
+ </attr>
+ <!-- The lineJoin for a stroked path -->
+ <attr name="strokeLineJoin" format="enum">
+ <enum name="miter" value="0"/>
+ <enum name="round" value="1"/>
+ <enum name="bevel" value="2"/>
+ </attr>
+ <!-- The Miter limit for a stroked path -->
+ <attr name="strokeMiterLimit" format="float"/>
+ </declare-styleable>
+
+ <!-- Defines the clip path used in VectorDrawables. -->
+ <declare-styleable name="VectorDrawableClipPath">
+ <!-- The Name of this path -->
+ <attr name="name" />
+ <!-- The specification of the operations that define the path -->
+ <attr name="pathData"/>
+ </declare-styleable>
+
+ <!-- ========================== -->
+ <!-- AnimatedVectorDrawable class -->
+ <!-- ========================== -->
+ <eat-comment />
+
+ <!-- Define the AnimatedVectorDrawable. -->
+ <declare-styleable name="AnimatedVectorDrawable">
+ <!-- The static vector drawable. -->
+ <attr name="drawable" format="reference" />
+ </declare-styleable>
+
+ <!-- Defines the target used in the AnimatedVectorDrawable. -->
+ <declare-styleable name="AnimatedVectorDrawableTarget">
+ <!-- The name of the target path, group or vector drawable -->
+ <attr name="name" />
+ <!-- The animation for the target path, group or vector drawable -->
+ <attr name="animation" />
+ </declare-styleable>
+</resources>
diff --git a/graphics/drawable/runavdtest.sh b/graphics/drawable/runavdtest.sh
new file mode 100755
index 0000000..023ad3e
--- /dev/null
+++ b/graphics/drawable/runavdtest.sh
@@ -0,0 +1,5 @@
+. ../../../../build/envsetup.sh
+mmm -j20 . && mmm -j20 ./testanimated/ && \
+adb install -r $OUT/data/app/AndroidAnimatedVectorDrawableTests/AndroidAnimatedVectorDrawableTests.apk && \
+adb shell am start -n android.support.test.vectordrawable/android.support.test.vectordrawable.TestAVDActivity
+
diff --git a/graphics/drawable/runtest.sh b/graphics/drawable/runtest.sh
new file mode 100755
index 0000000..6f69780
--- /dev/null
+++ b/graphics/drawable/runtest.sh
@@ -0,0 +1,5 @@
+. ../../../../build/envsetup.sh
+mmm -j20 . && mmm -j20 ./teststatic/ && \
+adb install -r $OUT/data/app/AndroidVectorDrawableTests/AndroidVectorDrawableTests.apk && \
+adb shell am start -n android.support.test.vectordrawable/android.support.test.vectordrawable.TestActivity
+
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
new file mode 100644
index 0000000..a92c3e5
--- /dev/null
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.support.graphics.drawable;
+
+import android.graphics.Path;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+// This class is a duplicate from the PathParser.java of frameworks/base, with slight
+// update on incompatible API like copyOfRange().
+class PathParser {
+ private static final String LOGTAG = "PathParser";
+
+ // Copy from Arrays.copyOfRange() which is only available from API level 9.
+ /**
+ * Copies elements from {@code original} into a new array, from indexes start (inclusive) to
+ * end (exclusive). The original order of elements is preserved.
+ * If {@code end} is greater than {@code original.length}, the result is padded
+ * with the value {@code 0.0f}.
+ *
+ * @param original the original array
+ * @param start the start index, inclusive
+ * @param end the end index, exclusive
+ * @return the new array
+ * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}
+ * @throws IllegalArgumentException if {@code start > end}
+ * @throws NullPointerException if {@code original == null}
+ */
+ private static float[] copyOfRange(float[] original, int start, int end) {
+ if (start > end) {
+ throw new IllegalArgumentException();
+ }
+ int originalLength = original.length;
+ if (start < 0 || start > originalLength) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ int resultLength = end - start;
+ int copyLength = Math.min(resultLength, originalLength - start);
+ float[] result = new float[resultLength];
+ System.arraycopy(original, start, result, 0, copyLength);
+ return result;
+ }
+
+ /**
+ * @param pathData The string representing a path, the same as "d" string in svg file.
+ * @return the generated Path object.
+ */
+ public static Path createPathFromPathData(String pathData) {
+ Path path = new Path();
+ PathDataNode[] nodes = createNodesFromPathData(pathData);
+ if (nodes != null) {
+ try {
+ PathDataNode.nodesToPath(nodes, path);
+ } catch (RuntimeException e) {
+ throw new RuntimeException("Error in parsing " + pathData, e);
+ }
+ return path;
+ }
+ return null;
+ }
+
+ /**
+ * @param pathData The string representing a path, the same as "d" string in svg file.
+ * @return an array of the PathDataNode.
+ */
+ public static PathDataNode[] createNodesFromPathData(String pathData) {
+ if (pathData == null) {
+ return null;
+ }
+ int start = 0;
+ int end = 1;
+
+ ArrayList<PathDataNode> list = new ArrayList<PathDataNode>();
+ while (end < pathData.length()) {
+ end = nextStart(pathData, end);
+ String s = pathData.substring(start, end).trim();
+ if (s.length() > 0) {
+ float[] val = getFloats(s);
+ addNode(list, s.charAt(0), val);
+ }
+
+ start = end;
+ end++;
+ }
+ if ((end - start) == 1 && start < pathData.length()) {
+ addNode(list, pathData.charAt(start), new float[0]);
+ }
+ return list.toArray(new PathDataNode[list.size()]);
+ }
+
+ /**
+ * @param source The array of PathDataNode to be duplicated.
+ * @return a deep copy of the <code>source</code>.
+ */
+ public static PathDataNode[] deepCopyNodes(PathDataNode[] source) {
+ if (source == null) {
+ return null;
+ }
+ PathDataNode[] copy = new PathParser.PathDataNode[source.length];
+ for (int i = 0; i < source.length; i ++) {
+ copy[i] = new PathDataNode(source[i]);
+ }
+ return copy;
+ }
+
+ /**
+ * @param nodesFrom The source path represented in an array of PathDataNode
+ * @param nodesTo The target path represented in an array of PathDataNode
+ * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
+ */
+ public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
+ if (nodesFrom == null || nodesTo == null) {
+ return false;
+ }
+
+ if (nodesFrom.length != nodesTo.length) {
+ return false;
+ }
+
+ for (int i = 0; i < nodesFrom.length; i ++) {
+ if (nodesFrom[i].mType != nodesTo[i].mType
+ || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Update the target's data to match the source.
+ * Before calling this, make sure canMorph(target, source) is true.
+ *
+ * @param target The target path represented in an array of PathDataNode
+ * @param source The source path represented in an array of PathDataNode
+ */
+ public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
+ for (int i = 0; i < source.length; i ++) {
+ target[i].mType = source[i].mType;
+ for (int j = 0; j < source[i].mParams.length; j ++) {
+ target[i].mParams[j] = source[i].mParams[j];
+ }
+ }
+ }
+
+ private static int nextStart(String s, int end) {
+ char c;
+
+ while (end < s.length()) {
+ c = s.charAt(end);
+ // Note that 'e' or 'E' are not valid path commands, but could be
+ // used for floating point numbers' scientific notation.
+ // Therefore, when searching for next command, we should ignore 'e'
+ // and 'E'.
+ if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
+ && c != 'e' && c != 'E') {
+ return end;
+ }
+ end++;
+ }
+ return end;
+ }
+
+ private static void addNode(ArrayList<PathDataNode> list, char cmd, float[] val) {
+ list.add(new PathDataNode(cmd, val));
+ }
+
+ private static class ExtractFloatResult {
+ // We need to return the position of the next separator and whether the
+ // next float starts with a '-' or a '.'.
+ int mEndPosition;
+ boolean mEndWithNegOrDot;
+ }
+
+ /**
+ * Parse the floats in the string.
+ * This is an optimized version of parseFloat(s.split(",|\\s"));
+ *
+ * @param s the string containing a command and list of floats
+ * @return array of floats
+ */
+ private static float[] getFloats(String s) {
+ if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
+ return new float[0];
+ }
+ try {
+ float[] results = new float[s.length()];
+ int count = 0;
+ int startPosition = 1;
+ int endPosition = 0;
+
+ ExtractFloatResult result = new ExtractFloatResult();
+ int totalLength = s.length();
+
+ // The startPosition should always be the first character of the
+ // current number, and endPosition is the character after the current
+ // number.
+ while (startPosition < totalLength) {
+ extract(s, startPosition, result);
+ endPosition = result.mEndPosition;
+
+ if (startPosition < endPosition) {
+ results[count++] = Float.parseFloat(
+ s.substring(startPosition, endPosition));
+ }
+
+ if (result.mEndWithNegOrDot) {
+ // Keep the '-' or '.' sign with next number.
+ startPosition = endPosition;
+ } else {
+ startPosition = endPosition + 1;
+ }
+ }
+ return copyOfRange(results, 0, count);
+ } catch (NumberFormatException e) {
+ throw new RuntimeException("error in parsing \"" + s + "\"", e);
+ }
+ }
+
+ /**
+ * Calculate the position of the next comma or space or negative sign
+ * @param s the string to search
+ * @param start the position to start searching
+ * @param result the result of the extraction, including the position of the
+ * the starting position of next number, whether it is ending with a '-'.
+ */
+ private static void extract(String s, int start, ExtractFloatResult result) {
+ // Now looking for ' ', ',', '.' or '-' from the start.
+ int currentIndex = start;
+ boolean foundSeparator = false;
+ result.mEndWithNegOrDot = false;
+ boolean secondDot = false;
+ boolean isExponential = false;
+ for (; currentIndex < s.length(); currentIndex++) {
+ boolean isPrevExponential = isExponential;
+ isExponential = false;
+ char currentChar = s.charAt(currentIndex);
+ switch (currentChar) {
+ case ' ':
+ case ',':
+ foundSeparator = true;
+ break;
+ case '-':
+ // The negative sign following a 'e' or 'E' is not a separator.
+ if (currentIndex != start && !isPrevExponential) {
+ foundSeparator = true;
+ result.mEndWithNegOrDot = true;
+ }
+ break;
+ case '.':
+ if (!secondDot) {
+ secondDot = true;
+ } else {
+ // This is the second dot, and it is considered as a separator.
+ foundSeparator = true;
+ result.mEndWithNegOrDot = true;
+ }
+ break;
+ case 'e':
+ case 'E':
+ isExponential = true;
+ break;
+ }
+ if (foundSeparator) {
+ break;
+ }
+ }
+ // When there is nothing found, then we put the end position to the end
+ // of the string.
+ result.mEndPosition = currentIndex;
+ }
+
+ /**
+ * Each PathDataNode represents one command in the "d" attribute of the svg
+ * file.
+ * An array of PathDataNode can represent the whole "d" attribute.
+ */
+ public static class PathDataNode {
+ private char mType;
+ private float[] mParams;
+
+ private PathDataNode(char type, float[] params) {
+ mType = type;
+ mParams = params;
+ }
+
+ private PathDataNode(PathDataNode n) {
+ mType = n.mType;
+ mParams = copyOfRange(n.mParams, 0, n.mParams.length);
+ }
+
+ /**
+ * Convert an array of PathDataNode to Path.
+ *
+ * @param node The source array of PathDataNode.
+ * @param path The target Path object.
+ */
+ public static void nodesToPath(PathDataNode[] node, Path path) {
+ float[] current = new float[6];
+ char previousCommand = 'm';
+ for (int i = 0; i < node.length; i++) {
+ addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
+ previousCommand = node[i].mType;
+ }
+ }
+
+ /**
+ * The current PathDataNode will be interpolated between the
+ * <code>nodeFrom</code> and <code>nodeTo</code> according to the
+ * <code>fraction</code>.
+ *
+ * @param nodeFrom The start value as a PathDataNode.
+ * @param nodeTo The end value as a PathDataNode
+ * @param fraction The fraction to interpolate.
+ */
+ public void interpolatePathDataNode(PathDataNode nodeFrom,
+ PathDataNode nodeTo, float fraction) {
+ for (int i = 0; i < nodeFrom.mParams.length; i++) {
+ mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
+ + nodeTo.mParams[i] * fraction;
+ }
+ }
+
+ private static void addCommand(Path path, float[] current,
+ char previousCmd, char cmd, float[] val) {
+
+ int incr = 2;
+ float currentX = current[0];
+ float currentY = current[1];
+ float ctrlPointX = current[2];
+ float ctrlPointY = current[3];
+ float currentSegmentStartX = current[4];
+ float currentSegmentStartY = current[5];
+ float reflectiveCtrlPointX;
+ float reflectiveCtrlPointY;
+
+ switch (cmd) {
+ case 'z':
+ case 'Z':
+ path.close();
+ // Path is closed here, but we need to move the pen to the
+ // closed position. So we cache the segment's starting position,
+ // and restore it here.
+ currentX = currentSegmentStartX;
+ currentY = currentSegmentStartY;
+ ctrlPointX = currentSegmentStartX;
+ ctrlPointY = currentSegmentStartY;
+ path.moveTo(currentX, currentY);
+ break;
+ case 'm':
+ case 'M':
+ case 'l':
+ case 'L':
+ case 't':
+ case 'T':
+ incr = 2;
+ break;
+ case 'h':
+ case 'H':
+ case 'v':
+ case 'V':
+ incr = 1;
+ break;
+ case 'c':
+ case 'C':
+ incr = 6;
+ break;
+ case 's':
+ case 'S':
+ case 'q':
+ case 'Q':
+ incr = 4;
+ break;
+ case 'a':
+ case 'A':
+ incr = 7;
+ break;
+ }
+
+ for (int k = 0; k < val.length; k += incr) {
+ switch (cmd) {
+ case 'm': // moveto - Start a new sub-path (relative)
+ path.rMoveTo(val[k + 0], val[k + 1]);
+ currentX += val[k + 0];
+ currentY += val[k + 1];
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ break;
+ case 'M': // moveto - Start a new sub-path
+ path.moveTo(val[k + 0], val[k + 1]);
+ currentX = val[k + 0];
+ currentY = val[k + 1];
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ break;
+ case 'l': // lineto - Draw a line from the current point (relative)
+ path.rLineTo(val[k + 0], val[k + 1]);
+ currentX += val[k + 0];
+ currentY += val[k + 1];
+ break;
+ case 'L': // lineto - Draw a line from the current point
+ path.lineTo(val[k + 0], val[k + 1]);
+ currentX = val[k + 0];
+ currentY = val[k + 1];
+ break;
+ case 'h': // horizontal lineto - Draws a horizontal line (relative)
+ path.rLineTo(val[k + 0], 0);
+ currentX += val[k + 0];
+ break;
+ case 'H': // horizontal lineto - Draws a horizontal line
+ path.lineTo(val[k + 0], currentY);
+ currentX = val[k + 0];
+ break;
+ case 'v': // vertical lineto - Draws a vertical line from the current point (r)
+ path.rLineTo(0, val[k + 0]);
+ currentY += val[k + 0];
+ break;
+ case 'V': // vertical lineto - Draws a vertical line from the current point
+ path.lineTo(currentX, val[k + 0]);
+ currentY = val[k + 0];
+ break;
+ case 'c': // curveto - Draws a cubic Bézier curve (relative)
+ path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+ val[k + 4], val[k + 5]);
+
+ ctrlPointX = currentX + val[k + 2];
+ ctrlPointY = currentY + val[k + 3];
+ currentX += val[k + 4];
+ currentY += val[k + 5];
+
+ break;
+ case 'C': // curveto - Draws a cubic Bézier curve
+ path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+ val[k + 4], val[k + 5]);
+ currentX = val[k + 4];
+ currentY = val[k + 5];
+ ctrlPointX = val[k + 2];
+ ctrlPointY = val[k + 3];
+ break;
+ case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'c' || previousCmd == 's'
+ || previousCmd == 'C' || previousCmd == 'S') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1],
+ val[k + 2], val[k + 3]);
+
+ ctrlPointX = currentX + val[k + 0];
+ ctrlPointY = currentY + val[k + 1];
+ currentX += val[k + 2];
+ currentY += val[k + 3];
+ break;
+ case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'c' || previousCmd == 's'
+ || previousCmd == 'C' || previousCmd == 'S') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+ ctrlPointX = val[k + 0];
+ ctrlPointY = val[k + 1];
+ currentX = val[k + 2];
+ currentY = val[k + 3];
+ break;
+ case 'q': // Draws a quadratic Bézier (relative)
+ path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+ ctrlPointX = currentX + val[k + 0];
+ ctrlPointY = currentY + val[k + 1];
+ currentX += val[k + 2];
+ currentY += val[k + 3];
+ break;
+ case 'Q': // Draws a quadratic Bézier
+ path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+ ctrlPointX = val[k + 0];
+ ctrlPointY = val[k + 1];
+ currentX = val[k + 2];
+ currentY = val[k + 3];
+ break;
+ case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'q' || previousCmd == 't'
+ || previousCmd == 'Q' || previousCmd == 'T') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1]);
+ ctrlPointX = currentX + reflectiveCtrlPointX;
+ ctrlPointY = currentY + reflectiveCtrlPointY;
+ currentX += val[k + 0];
+ currentY += val[k + 1];
+ break;
+ case 'T': // Draws a quadratic Bézier curve (reflective control point)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'q' || previousCmd == 't'
+ || previousCmd == 'Q' || previousCmd == 'T') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+ val[k + 0], val[k + 1]);
+ ctrlPointX = reflectiveCtrlPointX;
+ ctrlPointY = reflectiveCtrlPointY;
+ currentX = val[k + 0];
+ currentY = val[k + 1];
+ break;
+ case 'a': // Draws an elliptical arc
+ // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
+ drawArc(path,
+ currentX,
+ currentY,
+ val[k + 5] + currentX,
+ val[k + 6] + currentY,
+ val[k + 0],
+ val[k + 1],
+ val[k + 2],
+ val[k + 3] != 0,
+ val[k + 4] != 0);
+ currentX += val[k + 5];
+ currentY += val[k + 6];
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
+ break;
+ case 'A': // Draws an elliptical arc
+ drawArc(path,
+ currentX,
+ currentY,
+ val[k + 5],
+ val[k + 6],
+ val[k + 0],
+ val[k + 1],
+ val[k + 2],
+ val[k + 3] != 0,
+ val[k + 4] != 0);
+ currentX = val[k + 5];
+ currentY = val[k + 6];
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
+ break;
+ }
+ previousCmd = cmd;
+ }
+ current[0] = currentX;
+ current[1] = currentY;
+ current[2] = ctrlPointX;
+ current[3] = ctrlPointY;
+ current[4] = currentSegmentStartX;
+ current[5] = currentSegmentStartY;
+ }
+
+ private static void drawArc(Path p,
+ float x0,
+ float y0,
+ float x1,
+ float y1,
+ float a,
+ float b,
+ float theta,
+ boolean isMoreThanHalf,
+ boolean isPositiveArc) {
+
+ /* Convert rotation angle from degrees to radians */
+ double thetaD = Math.toRadians(theta);
+ /* Pre-compute rotation matrix entries */
+ double cosTheta = Math.cos(thetaD);
+ double sinTheta = Math.sin(thetaD);
+ /* Transform (x0, y0) and (x1, y1) into unit space */
+ /* using (inverse) rotation, followed by (inverse) scale */
+ double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
+ double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
+ double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
+ double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
+
+ /* Compute differences and averages */
+ double dx = x0p - x1p;
+ double dy = y0p - y1p;
+ double xm = (x0p + x1p) / 2;
+ double ym = (y0p + y1p) / 2;
+ /* Solve for intersecting unit circles */
+ double dsq = dx * dx + dy * dy;
+ if (dsq == 0.0) {
+ Log.w(LOGTAG, " Points are coincident");
+ return; /* Points are coincident */
+ }
+ double disc = 1.0 / dsq - 1.0 / 4.0;
+ if (disc < 0.0) {
+ Log.w(LOGTAG, "Points are too far apart " + dsq);
+ float adjust = (float) (Math.sqrt(dsq) / 1.99999);
+ drawArc(p, x0, y0, x1, y1, a * adjust,
+ b * adjust, theta, isMoreThanHalf, isPositiveArc);
+ return; /* Points are too far apart */
+ }
+ double s = Math.sqrt(disc);
+ double sdx = s * dx;
+ double sdy = s * dy;
+ double cx;
+ double cy;
+ if (isMoreThanHalf == isPositiveArc) {
+ cx = xm - sdy;
+ cy = ym + sdx;
+ } else {
+ cx = xm + sdy;
+ cy = ym - sdx;
+ }
+
+ double eta0 = Math.atan2((y0p - cy), (x0p - cx));
+
+ double eta1 = Math.atan2((y1p - cy), (x1p - cx));
+
+ double sweep = (eta1 - eta0);
+ if (isPositiveArc != (sweep >= 0)) {
+ if (sweep > 0) {
+ sweep -= 2 * Math.PI;
+ } else {
+ sweep += 2 * Math.PI;
+ }
+ }
+
+ cx *= a;
+ cy *= b;
+ double tcx = cx;
+ cx = cx * cosTheta - cy * sinTheta;
+ cy = tcx * sinTheta + cy * cosTheta;
+
+ arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
+ }
+
+ /**
+ * Converts an arc to cubic Bezier segments and records them in p.
+ *
+ * @param p The target for the cubic Bezier segments
+ * @param cx The x coordinate center of the ellipse
+ * @param cy The y coordinate center of the ellipse
+ * @param a The radius of the ellipse in the horizontal direction
+ * @param b The radius of the ellipse in the vertical direction
+ * @param e1x E(eta1) x coordinate of the starting point of the arc
+ * @param e1y E(eta2) y coordinate of the starting point of the arc
+ * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
+ * @param start The start angle of the arc on the ellipse
+ * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
+ */
+ private static void arcToBezier(Path p,
+ double cx,
+ double cy,
+ double a,
+ double b,
+ double e1x,
+ double e1y,
+ double theta,
+ double start,
+ double sweep) {
+ // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
+ // and http://www.spaceroots.org/documents/ellipse/node22.html
+
+ // Maximum of 45 degrees per cubic Bezier segment
+ int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
+
+ double eta1 = start;
+ double cosTheta = Math.cos(theta);
+ double sinTheta = Math.sin(theta);
+ double cosEta1 = Math.cos(eta1);
+ double sinEta1 = Math.sin(eta1);
+ double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
+ double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
+
+ double anglePerSegment = sweep / numSegments;
+ for (int i = 0; i < numSegments; i++) {
+ double eta2 = eta1 + anglePerSegment;
+ double sinEta2 = Math.sin(eta2);
+ double cosEta2 = Math.cos(eta2);
+ double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
+ double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
+ double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
+ double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
+ double tanDiff2 = Math.tan((eta2 - eta1) / 2);
+ double alpha =
+ Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
+ double q1x = e1x + alpha * ep1x;
+ double q1y = e1y + alpha * ep1y;
+ double q2x = e2x - alpha * ep2x;
+ double q2y = e2y - alpha * ep2y;
+
+ p.cubicTo((float) q1x,
+ (float) q1y,
+ (float) q2x,
+ (float) q2y,
+ (float) e2x,
+ (float) e2y);
+ eta1 = eta2;
+ e1x = e2x;
+ e1y = e2y;
+ ep1x = ep2x;
+ ep1y = ep2y;
+ }
+ }
+ }
+}
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
new file mode 100644
index 0000000..d33c204
--- /dev/null
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -0,0 +1,1470 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.support.graphics.drawable;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.DrawableRes;
+import android.support.v4.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Stack;
+
+/**
+ * This lets you create a drawable based on an XML vector graphic. It can be defined in an XML file
+ * with the <code><vector></code> element.
+ * <p/>
+ * The vector drawable has the following elements:
+ * <p/>
+ * <dt><code><vector></code></dt>
+ * <dl>
+ * <dd>Used to define a vector drawable
+ * <dl>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of this vector drawable.</dd>
+ * <dt><code>android:width</code></dt>
+ * <dd>Used to define the intrinsic width of the drawable. This support all the dimension units,
+ * normally specified with dp.</dd>
+ * <dt><code>android:height</code></dt>
+ * <dd>Used to define the intrinsic height the drawable. This support all the dimension units,
+ * normally specified with dp.</dd>
+ * <dt><code>android:viewportWidth</code></dt>
+ * <dd>Used to define the width of the viewport space. Viewport is basically the virtual canvas
+ * where the paths are drawn on.</dd>
+ * <dt><code>android:viewportHeight</code></dt>
+ * <dd>Used to define the height of the viewport space. Viewport is basically the virtual canvas
+ * where the paths are drawn on.</dd>
+ * <dt><code>android:tint</code></dt>
+ * <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
+ * <dt><code>android:tintMode</code></dt>
+ * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
+ * <dt><code>android:autoMirrored</code></dt>
+ * <dd>Indicates if the drawable needs to be mirrored when its layout direction is RTL
+ * (right-to-left).</dd>
+ * <dt><code>android:alpha</code></dt>
+ * <dd>The opacity of this drawable.</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ * <dl>
+ * <dt><code><group></code></dt>
+ * <dd>Defines a group of paths or subgroups, plus transformation information. The transformations
+ * are defined in the same coordinates as the viewport. And the transformations are applied in the
+ * order of scale, rotate then translate.
+ * <dl>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of the group.</dd>
+ * <dt><code>android:rotation</code></dt>
+ * <dd>The degrees of rotation of the group.</dd>
+ * <dt><code>android:pivotX</code></dt>
+ * <dd>The X coordinate of the pivot for the scale and rotation of the group. This is defined in the
+ * viewport space.</dd>
+ * <dt><code>android:pivotY</code></dt>
+ * <dd>The Y coordinate of the pivot for the scale and rotation of the group. This is defined in the
+ * viewport space.</dd>
+ * <dt><code>android:scaleX</code></dt>
+ * <dd>The amount of scale on the X Coordinate.</dd>
+ * <dt><code>android:scaleY</code></dt>
+ * <dd>The amount of scale on the Y coordinate.</dd>
+ * <dt><code>android:translateX</code></dt>
+ * <dd>The amount of translation on the X coordinate. This is defined in the viewport space.</dd>
+ * <dt><code>android:translateY</code></dt>
+ * <dd>The amount of translation on the Y coordinate. This is defined in the viewport space.</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ * <dl>
+ * <dt><code><path></code></dt>
+ * <dd>Defines paths to be drawn.
+ * <dl>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of the path.</dd>
+ * <dt><code>android:pathData</code></dt>
+ * <dd>Defines path data using exactly same format as "d" attribute in the SVG's path
+ * data. This is defined in the viewport space.</dd>
+ * <dt><code>android:fillColor</code></dt>
+ * <dd>Defines the color to fill the path (none if not present).</dd>
+ * <dt><code>android:strokeColor</code></dt>
+ * <dd>Defines the color to draw the path outline (none if not present).</dd>
+ * <dt><code>android:strokeWidth</code></dt>
+ * <dd>The width a path stroke.</dd>
+ * <dt><code>android:strokeAlpha</code></dt>
+ * <dd>The opacity of a path stroke.</dd>
+ * <dt><code>android:fillAlpha</code></dt>
+ * <dd>The opacity to fill the path with.</dd>
+ * <dt><code>android:trimPathStart</code></dt>
+ * <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
+ * <dt><code>android:trimPathEnd</code></dt>
+ * <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
+ * <dt><code>android:trimPathOffset</code></dt>
+ * <dd>Shift trim region (allows showed region to include the start and end), in the range from 0 to
+ * 1.</dd>
+ * <dt><code>android:strokeLineCap</code></dt>
+ * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
+ * <dt><code>android:strokeLineJoin</code></dt>
+ * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
+ * <dt><code>android:strokeMiterLimit</code></dt>
+ * <dd>Sets the Miter limit for a stroked path.</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ * <dl>
+ * <dt><code><clip-path></code></dt>
+ * <dd>Defines path to be the current clip.
+ * <dl>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of the clip path.</dd>
+ * <dt><code>android:pathData</code></dt>
+ * <dd>Defines clip path data using the same format as "d" attribute in the SVG's
+ * path data.</dd>
+ * </dl>
+ * </dd>
+ * </dl>
+ * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
+ * <pre>
+ * <vector xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:height="64dp"
+ * android:width="64dp"
+ * android:viewportHeight="600"
+ * android:viewportWidth="600" >
+ * <group
+ * android:name="rotationGroup"
+ * android:pivotX="300.0"
+ * android:pivotY="300.0"
+ * android:rotation="45.0" >
+ * <path
+ * android:name="v"
+ * android:fillColor="#000000"
+ * android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+ * </group>
+ * </vector>
+ * </pre></li>
+ */
+public class VectorDrawableCompat extends Drawable {
+ static final String LOGTAG = "VectorDrawableCompat";
+
+ static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
+
+ private static final String SHAPE_CLIP_PATH = "clip-path";
+ private static final String SHAPE_GROUP = "group";
+ private static final String SHAPE_PATH = "path";
+ private static final String SHAPE_VECTOR = "vector";
+
+ private static final int LINECAP_BUTT = 0;
+ private static final int LINECAP_ROUND = 1;
+ private static final int LINECAP_SQUARE = 2;
+
+ private static final int LINEJOIN_MITER = 0;
+ private static final int LINEJOIN_ROUND = 1;
+ private static final int LINEJOIN_BEVEL = 2;
+
+ private static final boolean DBG_VECTOR_DRAWABLE = true;
+
+ private VectorDrawableState mVectorState;
+
+ private PorterDuffColorFilter mTintFilter;
+ private ColorFilter mColorFilter;
+
+ private boolean mMutated;
+
+ // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise,
+ // caching the bitmap by default is allowed.
+ private boolean mAllowCaching = true;
+
+ private VectorDrawableCompat() {
+ mVectorState = new VectorDrawableState();
+ }
+
+ private VectorDrawableCompat(VectorDrawableState state) {
+ mVectorState = state;
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mVectorState = new VectorDrawableState(mVectorState);
+ mMutated = true;
+ }
+ return this;
+ }
+
+ Object getTargetByName(String name) {
+ return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ mVectorState.mChangingConfigurations = getChangingConfigurations();
+ return mVectorState;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ final Rect bounds = getBounds();
+ if (bounds.width() == 0 || bounds.height() == 0) {
+ // too small to draw
+ return;
+ }
+
+ final int saveCount = canvas.save();
+ final boolean needMirroring = needMirroring();
+
+ canvas.translate(bounds.left, bounds.top);
+ if (needMirroring) {
+ canvas.translate(bounds.width(), 0);
+ canvas.scale(-1.0f, 1.0f);
+ }
+
+ // Color filters always override tint filters.
+ final ColorFilter colorFilter = mColorFilter == null ? mTintFilter : mColorFilter;
+
+ if (!mAllowCaching) {
+ // AnimatedVectorDrawable
+ if (!mVectorState.hasTranslucentRoot()) {
+ mVectorState.mVPathRenderer.draw(
+ canvas, bounds.width(), bounds.height(), colorFilter);
+ } else {
+ mVectorState.createCachedBitmapIfNeeded(bounds);
+ mVectorState.updateCachedBitmap(bounds);
+ mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
+ }
+ } else {
+ // Static Vector Drawable case.
+ mVectorState.createCachedBitmapIfNeeded(bounds);
+ if (!mVectorState.canReuseCache()) {
+ mVectorState.updateCachedBitmap(bounds);
+ mVectorState.updateCacheStates();
+ }
+ mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter);
+ }
+
+ canvas.restoreToCount(saveCount);
+ }
+
+ public int getAlpha() {
+ return mVectorState.mVPathRenderer.getRootAlpha();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
+ mVectorState.mVPathRenderer.setRootAlpha(alpha);
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mColorFilter = colorFilter;
+ invalidateSelf();
+ }
+
+ /**
+ * Ensures the tint filter is consistent with the current tint color and
+ * mode.
+ */
+ PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
+ PorterDuff.Mode tintMode) {
+ if (tint == null || tintMode == null) {
+ return null;
+ }
+ // setMode, setColor of PorterDuffColorFilter are not public method in SDK v7.
+ // Therefore we create a new one all the time here. Don't expect this is called often.
+ final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+ return new PorterDuffColorFilter(color, tintMode);
+ }
+
+ public void setTint(int tint) {
+ setTintList(ColorStateList.valueOf(tint));
+ }
+
+ public void setTintList(ColorStateList tint) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTint != tint) {
+ state.mTint = tint;
+ mTintFilter = updateTintFilter(mTintFilter, tint, state.mTintMode);
+ invalidateSelf();
+ }
+ }
+
+ public void setTintMode(Mode tintMode) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTintMode != tintMode) {
+ state.mTintMode = tintMode;
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, tintMode);
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public boolean isStateful() {
+ return super.isStateful() || (mVectorState != null && mVectorState.mTint != null
+ && mVectorState.mTint.isStateful());
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTint != null && state.mTintMode != null) {
+ // mTintFilter = updateTintFilter(this, mTintFilter, state.mTint, state.mTintMode);
+ invalidateSelf();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return (int) mVectorState.mVPathRenderer.mBaseWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return (int) mVectorState.mVPathRenderer.mBaseHeight;
+ }
+
+ // Don't support re-applying themes. The initial theme loading is working.
+ public boolean canApplyTheme() {
+ return false;
+ }
+
+ /**
+ * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension. This
+ * is used to calculate the path animation accuracy.
+ *
+ * @hide
+ */
+ public float getPixelSize() {
+ if (mVectorState == null && mVectorState.mVPathRenderer == null ||
+ mVectorState.mVPathRenderer.mBaseWidth == 0 ||
+ mVectorState.mVPathRenderer.mBaseHeight == 0 ||
+ mVectorState.mVPathRenderer.mViewportHeight == 0 ||
+ mVectorState.mVPathRenderer.mViewportWidth == 0) {
+ return 1; // fall back to 1:1 pixel mapping.
+ }
+ float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
+ float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
+ float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
+ float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
+ float scaleX = viewportWidth / intrinsicWidth;
+ float scaleY = viewportHeight / intrinsicHeight;
+ return Math.min(scaleX, scaleY);
+ }
+
+ /**
+ * Create a VectorDrawableCompat object.
+ *
+ * @param res the resources.
+ * @param resId the resource ID for VectorDrawableCompat object.
+ * @param theme the theme of this vector drawable, it can be null.
+ * @return a new VectorDrawableCompat or null if parsing error is found.
+ */
+ @Nullable
+ public static VectorDrawableCompat create(@NonNull Resources res, @DrawableRes int resId,
+ @Nullable Theme theme) {
+ try {
+ final XmlPullParser parser = res.getXml(resId);
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ final VectorDrawableCompat drawable = new VectorDrawableCompat();
+ drawable.inflate(res, parser, attrs, theme);
+
+ return drawable;
+ } catch (XmlPullParserException e) {
+ Log.e(LOGTAG, "parser error", e);
+ } catch (IOException e) {
+ Log.e(LOGTAG, "parser error", e);
+ }
+ return null;
+ }
+
+ private static int applyAlpha(int color, float alpha) {
+ int alphaBytes = Color.alpha(color);
+ color &= 0x00FFFFFF;
+ color |= ((int) (alphaBytes * alpha)) << 24;
+ return color;
+ }
+
+ /**
+ * Obtains styled attributes from the theme, if available, or unstyled
+ * resources if the theme is null.
+ */
+ static TypedArray obtainAttributes(
+ Resources res, Theme theme, AttributeSet set, int[] attrs) {
+ if (theme == null) {
+ return res.obtainAttributes(set, attrs);
+ }
+ return theme.obtainStyledAttributes(set, attrs, 0, 0);
+ }
+
+
+ @Override
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ inflate(res, parser, attrs, null);
+ }
+
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+ final VectorDrawableState state = mVectorState;
+ final VPathRenderer pathRenderer = new VPathRenderer();
+ state.mVPathRenderer = pathRenderer;
+
+ final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ state.mChangingConfigurations = getChangingConfigurations();
+ state.mCacheDirty = true;
+ inflateInternal(res, parser, attrs, theme);
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+ final VectorDrawableState state = mVectorState;
+ final VPathRenderer pathRenderer = state.mVPathRenderer;
+
+ // Account for any configuration changes.
+ // state.mChangingConfigurations |= Utils.getChangingConfigurations(a);
+
+ final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
+ // if (tintMode != -1) {
+ // state.mTintMode = Utils.parseTintMode(tintMode, DEFAULT_TINT_MODE);
+ // }
+
+ final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
+ if (tint != null) {
+ state.mTint = tint;
+ }
+
+ state.mAutoMirrored = a.getBoolean(
+ R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
+
+ pathRenderer.mViewportWidth = a.getFloat(
+ R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
+ pathRenderer.mViewportHeight = a.getFloat(
+ R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+
+ if (pathRenderer.mViewportWidth <= 0) {
+ throw new XmlPullParserException(a.getPositionDescription() +
+ "<vector> tag requires viewportWidth > 0");
+ } else if (pathRenderer.mViewportHeight <= 0) {
+ throw new XmlPullParserException(a.getPositionDescription() +
+ "<vector> tag requires viewportHeight > 0");
+ }
+
+ pathRenderer.mBaseWidth = a.getDimension(
+ R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
+ pathRenderer.mBaseHeight = a.getDimension(
+ R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
+
+ if (pathRenderer.mBaseWidth <= 0) {
+ throw new XmlPullParserException(a.getPositionDescription() +
+ "<vector> tag requires width > 0");
+ } else if (pathRenderer.mBaseHeight <= 0) {
+ throw new XmlPullParserException(a.getPositionDescription() +
+ "<vector> tag requires height > 0");
+ }
+
+ final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
+ pathRenderer.getAlpha());
+ pathRenderer.setAlpha(alphaInFloat);
+
+ final String name = a.getString(R.styleable.VectorDrawable_name);
+ if (name != null) {
+ pathRenderer.mRootName = name;
+ pathRenderer.mVGTargetsMap.put(name, pathRenderer);
+ }
+ }
+
+ private void inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
+ Theme theme) throws XmlPullParserException, IOException {
+ final VectorDrawableState state = mVectorState;
+ final VPathRenderer pathRenderer = state.mVPathRenderer;
+ boolean noPathTag = true;
+
+ // Use a stack to help to build the group tree.
+ // The top of the stack is always the current group.
+ final Stack<VGroup> groupStack = new Stack<VGroup>();
+ groupStack.push(pathRenderer.mRootGroup);
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = parser.getName();
+ final VGroup currentGroup = groupStack.peek();
+ Log.v(LOGTAG, tagName);
+ if (SHAPE_PATH.equals(tagName)) {
+ final VFullPath path = new VFullPath();
+ path.inflate(res, attrs, theme);
+ currentGroup.mChildren.add(path);
+ if (path.getPathName() != null) {
+ pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+ }
+ noPathTag = false;
+ state.mChangingConfigurations |= path.mChangingConfigurations;
+ } else if (SHAPE_CLIP_PATH.equals(tagName)) {
+ final VClipPath path = new VClipPath();
+ path.inflate(res, attrs, theme);
+ currentGroup.mChildren.add(path);
+ if (path.getPathName() != null) {
+ pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+ }
+ state.mChangingConfigurations |= path.mChangingConfigurations;
+ } else if (SHAPE_GROUP.equals(tagName)) {
+ VGroup newChildGroup = new VGroup();
+ newChildGroup.inflate(res, attrs, theme);
+ currentGroup.mChildren.add(newChildGroup);
+ groupStack.push(newChildGroup);
+ if (newChildGroup.getGroupName() != null) {
+ pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
+ newChildGroup);
+ }
+ state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ final String tagName = parser.getName();
+ if (SHAPE_GROUP.equals(tagName)) {
+ groupStack.pop();
+ }
+ }
+ eventType = parser.next();
+ }
+
+ // Print the tree out for debug.
+ if (DBG_VECTOR_DRAWABLE) {
+ printGroupTree(pathRenderer.mRootGroup, 0);
+ }
+
+ if (noPathTag) {
+ final StringBuffer tag = new StringBuffer();
+
+ if (tag.length() > 0) {
+ tag.append(" or ");
+ }
+ tag.append(SHAPE_PATH);
+
+ throw new XmlPullParserException("no " + tag + " defined");
+ }
+ }
+
+ private void printGroupTree(VGroup currentGroup, int level) {
+ String indent = "";
+ for (int i = 0; i < level; i++) {
+ indent += " ";
+ }
+ // Print the current node
+ Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
+ + " rotation is " + currentGroup.mRotate);
+ Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
+ // Then print all the children groups
+ for (int i = 0; i < currentGroup.mChildren.size(); i++) {
+ Object child = currentGroup.mChildren.get(i);
+ if (child instanceof VGroup) {
+ printGroupTree((VGroup) child, level + 1);
+ }
+ }
+ }
+
+ void setAllowCaching(boolean allowCaching) {
+ mAllowCaching = allowCaching;
+ }
+
+ // We don't support RTL auto mirroring since the getLayoutDirection() is for API 17+.
+ private boolean needMirroring() {
+ return false;
+ }
+
+ private static class VectorDrawableState extends ConstantState {
+ int mChangingConfigurations;
+ VPathRenderer mVPathRenderer;
+ ColorStateList mTint = null;
+ Mode mTintMode = DEFAULT_TINT_MODE;
+ boolean mAutoMirrored;
+
+ Bitmap mCachedBitmap;
+ int[] mCachedThemeAttrs;
+ ColorStateList mCachedTint;
+ Mode mCachedTintMode;
+ int mCachedRootAlpha;
+ boolean mCachedAutoMirrored;
+ boolean mCacheDirty;
+
+ /** Temporary paint object used to draw cached bitmaps. */
+ Paint mTempPaint;
+
+ // Deep copy for mutate() or implicitly mutate.
+ public VectorDrawableState(VectorDrawableState copy) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
+ if (copy.mVPathRenderer.mFillPaint != null) {
+ mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
+ }
+ if (copy.mVPathRenderer.mStrokePaint != null) {
+ mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
+ }
+ mTint = copy.mTint;
+ mTintMode = copy.mTintMode;
+ mAutoMirrored = copy.mAutoMirrored;
+ }
+ }
+
+ public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter) {
+ // The bitmap's size is the same as the bounds.
+ final Paint p = getPaint(filter);
+ canvas.drawBitmap(mCachedBitmap, 0, 0, p);
+ }
+
+ public boolean hasTranslucentRoot() {
+ return mVPathRenderer.getRootAlpha() < 255;
+ }
+
+ /**
+ * @return null when there is no need for alpha paint.
+ */
+ public Paint getPaint(ColorFilter filter) {
+ if (!hasTranslucentRoot() && filter == null) {
+ return null;
+ }
+
+ if (mTempPaint == null) {
+ mTempPaint = new Paint();
+ mTempPaint.setFilterBitmap(true);
+ }
+ mTempPaint.setAlpha(mVPathRenderer.getRootAlpha());
+ mTempPaint.setColorFilter(filter);
+ return mTempPaint;
+ }
+
+ public void updateCachedBitmap(Rect bounds) {
+ mCachedBitmap.eraseColor(Color.TRANSPARENT);
+ Canvas tmpCanvas = new Canvas(mCachedBitmap);
+ mVPathRenderer.draw(tmpCanvas, bounds.width(), bounds.height(), null);
+ }
+
+ public void createCachedBitmapIfNeeded(Rect bounds) {
+ if (mCachedBitmap == null || !canReuseBitmap(bounds.width(),
+ bounds.height())) {
+ mCachedBitmap = Bitmap.createBitmap(bounds.width(), bounds.height(),
+ Bitmap.Config.ARGB_8888);
+ mCacheDirty = true;
+ }
+
+ }
+
+ public boolean canReuseBitmap(int width, int height) {
+ if (width == mCachedBitmap.getWidth()
+ && height == mCachedBitmap.getHeight()) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean canReuseCache() {
+ if (!mCacheDirty
+ && mCachedTint == mTint
+ && mCachedTintMode == mTintMode
+ && mCachedAutoMirrored == mAutoMirrored
+ && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
+ return true;
+ }
+ return false;
+ }
+
+ public void updateCacheStates() {
+ // Use shallow copy here and shallow comparison in canReuseCache(),
+ // likely hit cache miss more, but practically not much difference.
+ mCachedTint = mTint;
+ mCachedTintMode = mTintMode;
+ mCachedRootAlpha = mVPathRenderer.getRootAlpha();
+ mCachedAutoMirrored = mAutoMirrored;
+ mCacheDirty = false;
+ }
+
+ public VectorDrawableState() {
+ mVPathRenderer = new VPathRenderer();
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new VectorDrawableCompat(this);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new VectorDrawableCompat(this);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ private static class VPathRenderer {
+ /* Right now the internal data structure is organized as a tree.
+ * Each node can be a group node, or a path.
+ * A group node can have groups or paths as children, but a path node has
+ * no children.
+ * One example can be:
+ * Root Group
+ * / | \
+ * Group Path Group
+ * / \ |
+ * Path Path Path
+ *
+ */
+ // Variables that only used temporarily inside the draw() call, so there
+ // is no need for deep copying.
+ private final Path mPath;
+ private final Path mRenderPath;
+ private static final Matrix IDENTITY_MATRIX = new Matrix();
+ private final Matrix mFinalPathMatrix = new Matrix();
+
+ private Paint mStrokePaint;
+ private Paint mFillPaint;
+ private PathMeasure mPathMeasure;
+
+ /////////////////////////////////////////////////////
+ // Variables below need to be copied (deep copy if applicable) for mutation.
+ private int mChangingConfigurations;
+ private final VGroup mRootGroup;
+ float mBaseWidth = 0;
+ float mBaseHeight = 0;
+ float mViewportWidth = 0;
+ float mViewportHeight = 0;
+ int mRootAlpha = 0xFF;
+ String mRootName = null;
+
+ final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+
+ public VPathRenderer() {
+ mRootGroup = new VGroup();
+ mPath = new Path();
+ mRenderPath = new Path();
+ }
+
+ public void setRootAlpha(int alpha) {
+ mRootAlpha = alpha;
+ }
+
+ public int getRootAlpha() {
+ return mRootAlpha;
+ }
+
+ // setAlpha() and getAlpha() are used mostly for animation purpose, since
+ // Animator like to use alpha from 0 to 1.
+ public void setAlpha(float alpha) {
+ setRootAlpha((int) (alpha * 255));
+ }
+
+ @SuppressWarnings("unused")
+ public float getAlpha() {
+ return getRootAlpha() / 255.0f;
+ }
+
+ public VPathRenderer(VPathRenderer copy) {
+ mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
+ mPath = new Path(copy.mPath);
+ mRenderPath = new Path(copy.mRenderPath);
+ mBaseWidth = copy.mBaseWidth;
+ mBaseHeight = copy.mBaseHeight;
+ mViewportWidth = copy.mViewportWidth;
+ mViewportHeight = copy.mViewportHeight;
+ mChangingConfigurations = copy.mChangingConfigurations;
+ mRootAlpha = copy.mRootAlpha;
+ mRootName = copy.mRootName;
+ if (copy.mRootName != null) {
+ mVGTargetsMap.put(copy.mRootName, this);
+ }
+ }
+
+ private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
+ Canvas canvas, int w, int h, ColorFilter filter) {
+ // Calculate current group's matrix by preConcat the parent's and
+ // and the current one on the top of the stack.
+ // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+ // Mi the local matrix at level i of the group tree.
+ currentGroup.mStackedMatrix.set(currentMatrix);
+
+ currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
+
+ // Draw the group tree in the same order as the XML file.
+ for (int i = 0; i < currentGroup.mChildren.size(); i++) {
+ Object child = currentGroup.mChildren.get(i);
+ if (child instanceof VGroup) {
+ VGroup childGroup = (VGroup) child;
+ drawGroupTree(childGroup, currentGroup.mStackedMatrix,
+ canvas, w, h, filter);
+ } else if (child instanceof VPath) {
+ VPath childPath = (VPath) child;
+ drawPath(currentGroup, childPath, canvas, w, h, filter);
+ }
+ }
+ }
+
+ public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
+ // Travese the tree in pre-order to draw.
+ drawGroupTree(mRootGroup, IDENTITY_MATRIX, canvas, w, h, filter);
+ }
+
+ private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h,
+ ColorFilter filter) {
+ final float scaleX = w / mViewportWidth;
+ final float scaleY = h / mViewportHeight;
+ final float minScale = Math.min(scaleX, scaleY);
+
+ mFinalPathMatrix.set(vGroup.mStackedMatrix);
+ mFinalPathMatrix.postScale(scaleX, scaleY);
+
+ vPath.toPath(mPath);
+ final Path path = mPath;
+
+ mRenderPath.reset();
+
+ if (vPath.isClipPath()) {
+ mRenderPath.addPath(path, mFinalPathMatrix);
+ canvas.clipPath(mRenderPath, Region.Op.REPLACE);
+ } else {
+ VFullPath fullPath = (VFullPath) vPath;
+ if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
+ float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
+ float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
+
+ if (mPathMeasure == null) {
+ mPathMeasure = new PathMeasure();
+ }
+ mPathMeasure.setPath(mPath, false);
+
+ float len = mPathMeasure.getLength();
+ start = start * len;
+ end = end * len;
+ path.reset();
+ if (start > end) {
+ mPathMeasure.getSegment(start, len, path, true);
+ mPathMeasure.getSegment(0f, end, path, true);
+ } else {
+ mPathMeasure.getSegment(start, end, path, true);
+ }
+ path.rLineTo(0, 0); // fix bug in measure
+ }
+ mRenderPath.addPath(path, mFinalPathMatrix);
+
+ if (fullPath.mFillColor != Color.TRANSPARENT) {
+ if (mFillPaint == null) {
+ mFillPaint = new Paint();
+ mFillPaint.setStyle(Paint.Style.FILL);
+ mFillPaint.setAntiAlias(true);
+ }
+
+ final Paint fillPaint = mFillPaint;
+ fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
+ fillPaint.setColorFilter(filter);
+ canvas.drawPath(mRenderPath, fillPaint);
+ }
+
+ if (fullPath.mStrokeColor != Color.TRANSPARENT) {
+ if (mStrokePaint == null) {
+ mStrokePaint = new Paint();
+ mStrokePaint.setStyle(Paint.Style.STROKE);
+ mStrokePaint.setAntiAlias(true);
+ }
+
+ final Paint strokePaint = mStrokePaint;
+ if (fullPath.mStrokeLineJoin != null) {
+ strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
+ }
+
+ if (fullPath.mStrokeLineCap != null) {
+ strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
+ }
+
+ strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
+ strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
+ strokePaint.setColorFilter(filter);
+ strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale);
+ canvas.drawPath(mRenderPath, strokePaint);
+ }
+ }
+ }
+ }
+
+ private static class VGroup {
+ // mStackedMatrix is only used temporarily when drawing, it combines all
+ // the parents' local matrices with the current one.
+ private final Matrix mStackedMatrix = new Matrix();
+
+ /////////////////////////////////////////////////////
+ // Variables below need to be copied (deep copy if applicable) for mutation.
+ final ArrayList<Object> mChildren = new ArrayList<Object>();
+
+ private float mRotate = 0;
+ private float mPivotX = 0;
+ private float mPivotY = 0;
+ private float mScaleX = 1;
+ private float mScaleY = 1;
+ private float mTranslateX = 0;
+ private float mTranslateY = 0;
+
+ // mLocalMatrix is updated based on the update of transformation information,
+ // either parsed from the XML or by animation.
+ private final Matrix mLocalMatrix = new Matrix();
+ private int mChangingConfigurations;
+ private int[] mThemeAttrs;
+ private String mGroupName = null;
+
+ public VGroup(VGroup copy, ArrayMap<String, Object> targetsMap) {
+ mRotate = copy.mRotate;
+ mPivotX = copy.mPivotX;
+ mPivotY = copy.mPivotY;
+ mScaleX = copy.mScaleX;
+ mScaleY = copy.mScaleY;
+ mTranslateX = copy.mTranslateX;
+ mTranslateY = copy.mTranslateY;
+ mThemeAttrs = copy.mThemeAttrs;
+ mGroupName = copy.mGroupName;
+ mChangingConfigurations = copy.mChangingConfigurations;
+ if (mGroupName != null) {
+ targetsMap.put(mGroupName, this);
+ }
+
+ mLocalMatrix.set(copy.mLocalMatrix);
+
+ final ArrayList<Object> children = copy.mChildren;
+ for (int i = 0; i < children.size(); i++) {
+ Object copyChild = children.get(i);
+ if (copyChild instanceof VGroup) {
+ VGroup copyGroup = (VGroup) copyChild;
+ mChildren.add(new VGroup(copyGroup, targetsMap));
+ } else {
+ VPath newPath = null;
+ if (copyChild instanceof VFullPath) {
+ newPath = new VFullPath((VFullPath) copyChild);
+ } else if (copyChild instanceof VClipPath) {
+ newPath = new VClipPath((VClipPath) copyChild);
+ } else {
+ throw new IllegalStateException("Unknown object in the tree!");
+ }
+ mChildren.add(newPath);
+ if (newPath.mPathName != null) {
+ targetsMap.put(newPath.mPathName, newPath);
+ }
+ }
+ }
+ }
+
+ public VGroup() {
+ }
+
+ public String getGroupName() {
+ return mGroupName;
+ }
+
+ public Matrix getLocalMatrix() {
+ return mLocalMatrix;
+ }
+
+ public void inflate(Resources res, AttributeSet attrs, Theme theme) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.VectorDrawableGroup);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ // Account for any configuration changes.
+ // mChangingConfigurations |= Utils.getChangingConfigurations(a);
+
+ // Extract the theme attributes, if any.
+ mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
+
+ mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
+ mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
+ mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
+ mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
+ mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
+ mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
+ mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+
+ final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
+ if (groupName != null) {
+ mGroupName = groupName;
+ }
+
+ updateLocalMatrix();
+ }
+
+ private void updateLocalMatrix() {
+ // The order we apply is the same as the
+ // RenderNode.cpp::applyViewPropertyTransforms().
+ mLocalMatrix.reset();
+ mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
+ mLocalMatrix.postScale(mScaleX, mScaleY);
+ mLocalMatrix.postRotate(mRotate, 0, 0);
+ mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+ }
+
+ /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+ @SuppressWarnings("unused")
+ public float getRotation() {
+ return mRotate;
+ }
+
+ @SuppressWarnings("unused")
+ public void setRotation(float rotation) {
+ if (rotation != mRotate) {
+ mRotate = rotation;
+ updateLocalMatrix();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public float getPivotX() {
+ return mPivotX;
+ }
+
+ @SuppressWarnings("unused")
+ public void setPivotX(float pivotX) {
+ if (pivotX != mPivotX) {
+ mPivotX = pivotX;
+ updateLocalMatrix();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public float getPivotY() {
+ return mPivotY;
+ }
+
+ @SuppressWarnings("unused")
+ public void setPivotY(float pivotY) {
+ if (pivotY != mPivotY) {
+ mPivotY = pivotY;
+ updateLocalMatrix();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public float getScaleX() {
+ return mScaleX;
+ }
+
+ @SuppressWarnings("unused")
+ public void setScaleX(float scaleX) {
+ if (scaleX != mScaleX) {
+ mScaleX = scaleX;
+ updateLocalMatrix();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public float getScaleY() {
+ return mScaleY;
+ }
+
+ @SuppressWarnings("unused")
+ public void setScaleY(float scaleY) {
+ if (scaleY != mScaleY) {
+ mScaleY = scaleY;
+ updateLocalMatrix();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public float getTranslateX() {
+ return mTranslateX;
+ }
+
+ @SuppressWarnings("unused")
+ public void setTranslateX(float translateX) {
+ if (translateX != mTranslateX) {
+ mTranslateX = translateX;
+ updateLocalMatrix();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public float getTranslateY() {
+ return mTranslateY;
+ }
+
+ @SuppressWarnings("unused")
+ public void setTranslateY(float translateY) {
+ if (translateY != mTranslateY) {
+ mTranslateY = translateY;
+ updateLocalMatrix();
+ }
+ }
+ }
+
+ /**
+ * Common Path information for clip path and normal path.
+ */
+ private static class VPath {
+ protected PathParser.PathDataNode[] mNodes = null;
+ String mPathName;
+ int mChangingConfigurations;
+
+ public VPath() {
+ // Empty constructor.
+ }
+
+ public VPath(VPath copy) {
+ mPathName = copy.mPathName;
+ mChangingConfigurations = copy.mChangingConfigurations;
+ mNodes = PathParser.deepCopyNodes(copy.mNodes);
+ }
+
+ public void toPath(Path path) {
+ path.reset();
+ if (mNodes != null) {
+ PathParser.PathDataNode.nodesToPath(mNodes, path);
+ }
+ }
+
+ public String getPathName() {
+ return mPathName;
+ }
+
+ public boolean canApplyTheme() {
+ return false;
+ }
+
+ public void applyTheme(Theme t) {
+ }
+
+ public boolean isClipPath() {
+ return false;
+ }
+
+ /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+ @SuppressWarnings("unused")
+ public PathParser.PathDataNode[] getPathData() {
+ return mNodes;
+ }
+
+ @SuppressWarnings("unused")
+ public void setPathData(PathParser.PathDataNode[] nodes) {
+ if (!PathParser.canMorph(mNodes, nodes)) {
+ // This should not happen in the middle of animation.
+ mNodes = PathParser.deepCopyNodes(nodes);
+ } else {
+ PathParser.updateNodes(mNodes, nodes);
+ }
+ }
+ }
+
+ /**
+ * Clip path, which only has name and pathData.
+ */
+ private static class VClipPath extends VPath {
+ public VClipPath() {
+ // Empty constructor.
+ }
+
+ public VClipPath(VClipPath copy) {
+ super(copy);
+ }
+
+ public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ // TODO TINT THEME Not supported yet
+ final TypedArray a = obtainAttributes(r, theme, attrs,
+ R.styleable.VectorDrawableClipPath);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ // Account for any configuration changes.
+ // mChangingConfigurations |= Utils.getChangingConfigurations(a);;
+
+ final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+ if (pathName != null) {
+ mPathName = pathName;
+ }
+
+ final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+ if (pathData != null) {
+ mNodes = PathParser.createNodesFromPathData(pathData);
+ }
+ }
+
+ @Override
+ public boolean isClipPath() {
+ return true;
+ }
+ }
+
+ /**
+ * Normal path, which contains all the fill / paint information.
+ */
+ private static class VFullPath extends VPath {
+ /////////////////////////////////////////////////////
+ // Variables below need to be copied (deep copy if applicable) for mutation.
+ private int[] mThemeAttrs;
+
+ int mStrokeColor = Color.TRANSPARENT;
+ float mStrokeWidth = 0;
+
+ int mFillColor = Color.TRANSPARENT;
+ float mStrokeAlpha = 1.0f;
+ int mFillRule;
+ float mFillAlpha = 1.0f;
+ float mTrimPathStart = 0;
+ float mTrimPathEnd = 1;
+ float mTrimPathOffset = 0;
+
+ Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
+ Paint.Join mStrokeLineJoin = Paint.Join.MITER;
+ float mStrokeMiterlimit = 4;
+
+ public VFullPath() {
+ // Empty constructor.
+ }
+
+ public VFullPath(VFullPath copy) {
+ super(copy);
+ mThemeAttrs = copy.mThemeAttrs;
+
+ mStrokeColor = copy.mStrokeColor;
+ mStrokeWidth = copy.mStrokeWidth;
+ mStrokeAlpha = copy.mStrokeAlpha;
+ mFillColor = copy.mFillColor;
+ mFillRule = copy.mFillRule;
+ mFillAlpha = copy.mFillAlpha;
+ mTrimPathStart = copy.mTrimPathStart;
+ mTrimPathEnd = copy.mTrimPathEnd;
+ mTrimPathOffset = copy.mTrimPathOffset;
+
+ mStrokeLineCap = copy.mStrokeLineCap;
+ mStrokeLineJoin = copy.mStrokeLineJoin;
+ mStrokeMiterlimit = copy.mStrokeMiterlimit;
+ }
+
+ private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
+ switch (id) {
+ case LINECAP_BUTT:
+ return Paint.Cap.BUTT;
+ case LINECAP_ROUND:
+ return Paint.Cap.ROUND;
+ case LINECAP_SQUARE:
+ return Paint.Cap.SQUARE;
+ default:
+ return defValue;
+ }
+ }
+
+ private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
+ switch (id) {
+ case LINEJOIN_MITER:
+ return Paint.Join.MITER;
+ case LINEJOIN_ROUND:
+ return Paint.Join.ROUND;
+ case LINEJOIN_BEVEL:
+ return Paint.Join.BEVEL;
+ default:
+ return defValue;
+ }
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null;
+ }
+
+ public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ final TypedArray a = obtainAttributes(r, theme, attrs,
+ R.styleable.VectorDrawablePath);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ // Account for any configuration changes.
+ // mChangingConfigurations |= Utils.getChangingConfigurations(a);
+
+ // Extract the theme attributes, if any.
+ mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
+
+ final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+ if (pathName != null) {
+ mPathName = pathName;
+ }
+
+ final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+ if (pathData != null) {
+ mNodes = PathParser.createNodesFromPathData(pathData);
+ }
+
+ mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
+ mFillColor);
+ mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha,
+ mFillAlpha);
+ mStrokeLineCap = getStrokeLineCap(a.getInt(
+ R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
+ mStrokeLineJoin = getStrokeLineJoin(a.getInt(
+ R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
+ mStrokeMiterlimit = a.getFloat(
+ R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
+ mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
+ mStrokeColor);
+ mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
+ mStrokeAlpha);
+ mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
+ mStrokeWidth);
+ mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
+ mTrimPathEnd);
+ mTrimPathOffset = a.getFloat(
+ R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
+ mTrimPathStart = a.getFloat(
+ R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+ }
+
+ @Override
+ public void applyTheme(Theme t) {
+ if (mThemeAttrs == null) {
+ return;
+ }
+
+ /*
+ * TODO TINT THEME Not supported yet final TypedArray a =
+ * t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+ * updateStateFromTypedArray(a); a.recycle();
+ */
+ }
+
+ /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+ @SuppressWarnings("unused")
+ int getStrokeColor() {
+ return mStrokeColor;
+ }
+
+ @SuppressWarnings("unused")
+ void setStrokeColor(int strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+
+ @SuppressWarnings("unused")
+ float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ @SuppressWarnings("unused")
+ void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+
+ @SuppressWarnings("unused")
+ float getStrokeAlpha() {
+ return mStrokeAlpha;
+ }
+
+ @SuppressWarnings("unused")
+ void setStrokeAlpha(float strokeAlpha) {
+ mStrokeAlpha = strokeAlpha;
+ }
+
+ @SuppressWarnings("unused")
+ int getFillColor() {
+ return mFillColor;
+ }
+
+ @SuppressWarnings("unused")
+ void setFillColor(int fillColor) {
+ mFillColor = fillColor;
+ }
+
+ @SuppressWarnings("unused")
+ float getFillAlpha() {
+ return mFillAlpha;
+ }
+
+ @SuppressWarnings("unused")
+ void setFillAlpha(float fillAlpha) {
+ mFillAlpha = fillAlpha;
+ }
+
+ @SuppressWarnings("unused")
+ float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+
+ @SuppressWarnings("unused")
+ void setTrimPathStart(float trimPathStart) {
+ mTrimPathStart = trimPathStart;
+ }
+
+ @SuppressWarnings("unused")
+ float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+
+ @SuppressWarnings("unused")
+ void setTrimPathEnd(float trimPathEnd) {
+ mTrimPathEnd = trimPathEnd;
+ }
+
+ @SuppressWarnings("unused")
+ float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+
+ @SuppressWarnings("unused")
+ void setTrimPathOffset(float trimPathOffset) {
+ mTrimPathOffset = trimPathOffset;
+ }
+ }
+}
diff --git a/graphics/drawable/testanimated/Android.mk b/graphics/drawable/testanimated/Android.mk
new file mode 100644
index 0000000..c888d9e
--- /dev/null
+++ b/graphics/drawable/testanimated/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SDK_VERSION := 11
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR = \
+ $(LOCAL_PATH)/res \
+ frameworks/support/graphics/drawable/res \
+
+LOCAL_PACKAGE_NAME := AndroidAnimatedVectorDrawableTests
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v11-animatedvectordrawable android-support-v4
+
+LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages android.support.graphics.drawable
+
+include $(BUILD_PACKAGE)
diff --git a/graphics/drawable/testanimated/AndroidManifest.xml b/graphics/drawable/testanimated/AndroidManifest.xml
new file mode 100644
index 0000000..16171f2
--- /dev/null
+++ b/graphics/drawable/testanimated/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.test.vectordrawable" >
+
+ <uses-sdk android:minSdkVersion="11" />
+
+ <application android:icon="@drawable/app_sample_code" android:label="AnimatedVectorDrawableCompatTest" >
+ <activity android:name="android.support.test.vectordrawable.TestAVDActivity" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/anim/alpha_animation_progress_bar.xml b/graphics/drawable/testanimated/res/anim/alpha_animation_progress_bar.xml
new file mode 100644
index 0000000..2463a89
--- /dev/null
+++ b/graphics/drawable/testanimated/res/anim/alpha_animation_progress_bar.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="3350"
+ android:propertyName="alpha"
+ android:valueFrom="1"
+ android:valueTo="0.2" />
+
+</set>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/anim/animation_grouping_1_01.xml b/graphics/drawable/testanimated/res/anim/animation_grouping_1_01.xml
new file mode 100644
index 0000000..36c297f
--- /dev/null
+++ b/graphics/drawable/testanimated/res/anim/animation_grouping_1_01.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:duration="3300"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="450" />
diff --git a/graphics/drawable/testanimated/res/anim/trim_path_animation_progress_bar.xml b/graphics/drawable/testanimated/res/anim/trim_path_animation_progress_bar.xml
new file mode 100644
index 0000000..388c759
--- /dev/null
+++ b/graphics/drawable/testanimated/res/anim/trim_path_animation_progress_bar.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="1300"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="trimPathStart"
+ android:repeatCount="-1"
+ android:valueFrom="0"
+ android:valueTo="0.75"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="1300"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="trimPathEnd"
+ android:repeatCount="-1"
+ android:valueFrom="0.25"
+ android:valueTo="1.0"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="1300"
+ android:interpolator="@android:anim/linear_interpolator"
+ android:propertyName="trimPathOffset"
+ android:repeatCount="-1"
+ android:valueFrom="0"
+ android:valueTo="0.25"
+ android:valueType="floatType" />
+
+</set>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
new file mode 100644
index 0000000..7c3b1de
--- /dev/null
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:drawable="@drawable/vector_drawable_grouping_1" >
+
+ <target
+ auto:name="sun"
+ auto:animation="@anim/animation_grouping_1_01" />
+ <target
+ auto:name="earth"
+ auto:animation="@anim/animation_grouping_1_01" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
new file mode 100644
index 0000000..e37d2a1
--- /dev/null
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:drawable="@drawable/vector_drawable_progress_bar" >
+
+ <target
+ auto:name="pie1"
+ auto:animation="@anim/trim_path_animation_progress_bar" />
+ <target
+ auto:name="root_bar"
+ auto:animation="@anim/alpha_animation_progress_bar" />
+</animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/app_sample_code.png b/graphics/drawable/testanimated/res/drawable/app_sample_code.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/graphics/drawable/testanimated/res/drawable/app_sample_code.png
Binary files differ
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
new file mode 100644
index 0000000..eceda71
--- /dev/null
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
@@ -0,0 +1,53 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="256"
+ auto:viewportWidth="256" >
+
+ <group
+ auto:name="shape_layer_1"
+ auto:translateX="128"
+ auto:translateY="128" >
+ <group auto:name="sun" >
+ <path
+ auto:name="ellipse_path_1"
+ auto:fillColor="#ffff8000"
+ auto:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
+
+ <group
+ auto:name="earth"
+ auto:translateX="75" >
+ <path
+ auto:name="ellipse_path_1_1"
+ auto:fillColor="#ff5656ea"
+ auto:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
+
+ <group
+ auto:name="moon"
+ auto:translateX="25" >
+ <path
+ auto:name="ellipse_path_1_2"
+ auto:fillColor="#ffadadad"
+ auto:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
new file mode 100644
index 0000000..0b8884b
--- /dev/null
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="64"
+ auto:viewportWidth="64"
+ auto:name="root_bar" >
+
+ <group
+ auto:name="root"
+ auto:pivotX="0.0"
+ auto:pivotY="0.0"
+ auto:rotation="0"
+ auto:translateX="32.0"
+ auto:translateY="32.0" >
+ <group
+ auto:name="rotationGroup"
+ auto:pivotX="0.0"
+ auto:pivotY="0.0"
+ auto:rotation="0" >
+ <path
+ auto:name="pie1"
+ auto:fillColor="#00000000"
+ auto:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
+ auto:strokeColor="#FF00FFFF"
+ auto:strokeLineCap="round"
+ auto:strokeLineJoin="miter"
+ auto:strokeWidth="2"
+ auto:trimPathEnd="0.1"
+ auto:trimPathOffset="0"
+ auto:trimPathStart="0" />
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/values/strings.xml b/graphics/drawable/testanimated/res/values/strings.xml
new file mode 100644
index 0000000..c5451c8
--- /dev/null
+++ b/graphics/drawable/testanimated/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="twoLinePathData">"M 0,0 v 100 M 0,0 h 100"</string>
+ <string name="triangle"> "M300,70 l 0,-70 70,70 0,0 -70,70z"</string>
+ <string name="rectangle">"M300,70 l 0,-70 70,0 0,140 -70,0 z"</string>
+ <string name="rectangle2">"M300,70 l 0,-70 70,0 0,70z M300,70 l 70,0 0,70 -70,0z"</string>
+ <string name="equal2"> "M300,35 l 0,-35 70,0 0,35z M300,105 l 70,0 0,35 -70,0z"</string>
+ <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string>
+ <string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string>
+ <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
+</resources>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/src/android/support/test/vectordrawable/TestAVDActivity.java b/graphics/drawable/testanimated/src/android/support/test/vectordrawable/TestAVDActivity.java
new file mode 100644
index 0000000..c63c69f
--- /dev/null
+++ b/graphics/drawable/testanimated/src/android/support/test/vectordrawable/TestAVDActivity.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.test.vectordrawable;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.text.DecimalFormat;
+
+public class TestAVDActivity extends Activity implements View.OnClickListener{
+ private static final String LOG_TAG = "TestActivity";
+
+ private static final String LOGCAT = "VectorDrawable1";
+ protected int[] icon = {
+ R.drawable.animation_vector_drawable_grouping_1,
+ R.drawable.animation_vector_progress_bar,
+ };
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ObjectAnimator oa = new ObjectAnimator();
+ super.onCreate(savedInstanceState);
+ ScrollView scrollView = new ScrollView(this);
+ LinearLayout container = new LinearLayout(this);
+ scrollView.addView(container);
+ container.setOrientation(LinearLayout.VERTICAL);
+ Resources res = this.getResources();
+ container.setBackgroundColor(0xFF888888);
+ AnimatedVectorDrawableCompat []d = new AnimatedVectorDrawableCompat[icon.length];
+ long time = android.os.SystemClock.currentThreadTimeMillis();
+ for (int i = 0; i < icon.length; i++) {
+ d[i] = AnimatedVectorDrawableCompat.create(this, icon[i]);
+ }
+ time = android.os.SystemClock.currentThreadTimeMillis()-time;
+ TextView t = new TextView(this);
+ DecimalFormat df = new DecimalFormat("#.##");
+ t.setText("avgL=" + df.format(time / (icon.length)) + " ms");
+ container.addView(t);
+
+ addDrawableButtons(container, d);
+
+ // Now test constant state and mutate a bit.
+ AnimatedVectorDrawableCompat []copies = new AnimatedVectorDrawableCompat[3];
+ copies[0] = (AnimatedVectorDrawableCompat) d[0].getConstantState().newDrawable();
+ copies[1] = (AnimatedVectorDrawableCompat) d[0].getConstantState().newDrawable();
+ copies[2] = (AnimatedVectorDrawableCompat) d[0].getConstantState().newDrawable();
+ copies[0].setAlpha(128);
+
+ // Expect to see the copies[0, 1] are showing alpha 128, and [2] are showing 255.
+ copies[2].mutate();
+ copies[2].setAlpha(255);
+
+ addDrawableButtons(container, copies);
+
+ setContentView(scrollView);
+ }
+
+ private void addDrawableButtons(LinearLayout container, AnimatedVectorDrawableCompat[] d) {
+ for (int i = 0; i < d.length; i++) {
+ Button button = new Button(this);
+ button.setWidth(200);
+ button.setHeight(200);
+ button.setBackgroundDrawable(d[i]);
+ container.addView(button);
+ button.setOnClickListener(this);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ AnimatedVectorDrawableCompat d = (AnimatedVectorDrawableCompat) v.getBackground();
+ d.start();
+ }
+}
diff --git a/graphics/drawable/teststatic/Android.mk b/graphics/drawable/teststatic/Android.mk
new file mode 100644
index 0000000..d8a0fd7
--- /dev/null
+++ b/graphics/drawable/teststatic/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SDK_VERSION := 7
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR = \
+ $(LOCAL_PATH)/res \
+ frameworks/support/graphics/drawable/res \
+
+LOCAL_PACKAGE_NAME := AndroidVectorDrawableTests
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable android-support-v4
+
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay \
+ --extra-packages android.support.graphics.drawable
+
+include $(BUILD_PACKAGE)
+
diff --git a/graphics/drawable/teststatic/AndroidManifest.xml b/graphics/drawable/teststatic/AndroidManifest.xml
new file mode 100644
index 0000000..19586fb
--- /dev/null
+++ b/graphics/drawable/teststatic/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.test.vectordrawable" >
+
+ <uses-sdk android:minSdkVersion="7" />
+
+ <application android:icon="@drawable/app_sample_code" android:label="VectorDrawableCompatTest" >
+ <activity android:name="android.support.test.vectordrawable.TestActivity" />
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/app_sample_code.png b/graphics/drawable/teststatic/res/drawable/app_sample_code.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/app_sample_code.png
Binary files differ
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
new file mode 100644
index 0000000..12357ef
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="48dp"
+ auto:viewportHeight="480"
+ auto:viewportWidth="480"
+ auto:width="48dp" >
+
+ <group>
+ <path
+ auto:name="box1"
+ auto:fillColor="?android:attr/textColorPrimary"
+ auto:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
+ auto:strokeColor="?android:attr/colorBackground"
+ auto:strokeLineCap="round"
+ auto:strokeLineJoin="round" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
new file mode 100644
index 0000000..cb6b9df
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
@@ -0,0 +1,37 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:viewportHeight="320"
+ auto:viewportWidth="320"
+ auto:width="64dp" >
+
+ <group
+ auto:pivotX="70"
+ auto:pivotY="120"
+ auto:rotation="180" >
+ <path
+ auto:name="house"
+ auto:fillColor="#ff440000"
+ auto:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="10"
+ auto:trimPathEnd=".9"
+ auto:trimPathStart=".1" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
new file mode 100644
index 0000000..37d0086
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
@@ -0,0 +1,72 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:viewportHeight="12.25"
+ auto:viewportWidth="7.30625"
+ auto:width="64dp" >
+
+ <group
+ auto:pivotX="3.65"
+ auto:pivotY="6.125"
+ auto:rotation="-30" >
+ <clip-path
+ auto:name="clip1"
+ auto:pathData="
+ M 0, 6.125
+ l 7.3, 0
+ l 0, 12.25
+ l-7.3, 0
+ z" />
+ </group>
+ <group>
+ <path
+ auto:name="one"
+ auto:fillColor="#ff88ff"
+ auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+ l-5.046875,0.0 0.0-1.0Z" />
+ </group>
+ <group
+ auto:pivotX="3.65"
+ auto:pivotY="6.125"
+ auto:rotation="-30" >
+ <clip-path
+ auto:name="clip2"
+ auto:pathData="
+ M 0, 0
+ l 7.3, 0
+ l 0, 6.125
+ l-7.3, 0
+ z" />
+ </group>
+ <group>
+ <path
+ auto:name="two"
+ auto:fillColor="#ff88ff"
+ auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
+ q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
+ q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
+ q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875
+ q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
+ q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
+ q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
+ q-0.78125024,0.8125-2.2187502,2.265625Z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
new file mode 100644
index 0000000..4e2086f
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
@@ -0,0 +1,58 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:width="64dp"
+ auto:height="64dp"
+ auto:viewportWidth="7.30625"
+ auto:viewportHeight="12.25"
+ auto:autoMirrored="true">
+
+ <group>
+ <clip-path
+ auto:name="clip1"
+ auto:pathData="
+ M 3.65, 6.125
+ m-.001, 0
+ a .001,.001 0 1,0 .002,0
+ a .001,.001 0 1,0-.002,0z"/>
+ <path
+ auto:name="one"
+ auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+ l-5.046875,0.0 0.0-1.0Z"
+ auto:fillColor="#ff88ff"/>
+
+ <clip-path
+ auto:name="clip2"
+ auto:pathData="
+ M 3.65, 6.125
+ m-6, 0
+ a 6,6 0 1,0 12,0
+ a 6,6 0 1,0-12,0z"/>
+ <path
+ auto:name="two"
+ auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
+ q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
+ q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
+ q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875
+ q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
+ q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
+ q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
+ q-0.78125024,0.8125-2.2187502,2.265625Z"
+ auto:fillColor="#ff88ff"/>
+ </group>
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
new file mode 100644
index 0000000..48801e3
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
@@ -0,0 +1,44 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="12.25"
+ auto:viewportWidth="7.30625" >
+
+ <group>
+ <path
+ auto:name="one"
+ auto:fillColor="#ffff00"
+ auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+ l-5.046875,0.0 0.0-1.0Z" />
+ <path
+ auto:name="two"
+ auto:fillColor="#ffff00"
+ auto:fillAlpha="0"
+ auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
+ q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
+ q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
+ q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875
+ q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
+ q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
+ q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
+ q-0.78125024,0.8125-2.2187502,2.265625Z" />
+ </group>
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
new file mode 100644
index 0000000..24173e2
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
@@ -0,0 +1,49 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:width="64dp"
+ auto:height="64dp"
+ auto:viewportWidth="700"
+ auto:viewportHeight="700">
+
+ <group>
+ <path auto:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
+ auto:name="path2451"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#FF000000"
+ auto:strokeWidth="30.65500000000000"/>
+ <path auto:pathData="M 365.015 311.066"
+ auto:name="path2453"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#FF000000"
+ auto:strokeWidth="30.655000000000001"/>
+ <path auto:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
+ auto:name="path2455"
+ auto:strokeColor="#FF000000"
+ auto:fillColor="#FFFFFFFF"
+ auto:strokeWidth="30.655000000000001"/>
+ <path auto:pathData="M 170.515 451.566L 305.61 313.46"
+ auto:name="path2457"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#000000"
+ auto:strokeWidth="30.655000000000001"/>
+ <path auto:pathData="M 557.968 449.974L 426.515 315.375"
+ auto:name="path2459"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#000000"
+ auto:strokeWidth="30.655000000000001"/>
+ </group>
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
new file mode 100644
index 0000000..90435d3
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
@@ -0,0 +1,30 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:width="64dp"
+ auto:height="64dp" auto:viewportWidth="140"
+ auto:viewportHeight="110">
+
+ <group>
+ <path
+ auto:name="back"
+ auto:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
+ M 27,50 l 97,0 0,10-97,0 z
+ M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z"
+ auto:fillColor="#ffffffff"
+ />
+ </group>
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
new file mode 100644
index 0000000..251d694
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
@@ -0,0 +1,30 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:width="64dp"
+ auto:height="64dp" auto:viewportWidth="600"
+ auto:viewportHeight="600">
+
+ <group>
+ <path
+ auto:name="pie1"
+ auto:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
+ auto:fillColor="#ffffcc00"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="1"/>
+ </group>
+
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
new file mode 100644
index 0000000..eccb0d0
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
@@ -0,0 +1,33 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="200"
+ auto:viewportWidth="200" >
+
+ <group
+ auto:pivotX="100"
+ auto:pivotY="100"
+ auto:rotation="90">
+ <path
+ auto:name="house"
+ auto:fillColor="#ffffffff"
+ auto:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
new file mode 100644
index 0000000..b26d30d
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportWidth="200"
+ auto:viewportHeight="200">
+
+ <group>
+ <path
+ auto:name="bar3"
+ auto:fillColor="#FFFFFFFF"
+ auto:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
+ <path
+ auto:name="bar2"
+ auto:fillColor="#FFFFFFFF"
+ auto:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+ <path
+ auto:name="bar1"
+ auto:fillColor="#FF555555"
+ auto:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+ <path
+ auto:name="bar0"
+ auto:fillColor="#FF555555"
+ auto:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
new file mode 100644
index 0000000..eb440f5
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="80"
+ auto:viewportWidth="40" >
+
+ <group>
+ <path
+ auto:name="battery"
+ auto:fillColor="#3388ff"
+ auto:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+ auto:strokeColor="#ff8833"
+ auto:strokeWidth="1" />
+ <path
+ auto:name="spark"
+ auto:fillColor="#FFFF0000"
+ auto:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
new file mode 100644
index 0000000..94a23e8
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
@@ -0,0 +1,98 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:name="rootGroup"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="600"
+ auto:viewportWidth="600"
+ auto:alpha="0.5" >
+
+ <group
+ auto:name="rotationGroup"
+ auto:pivotX="300.0"
+ auto:pivotY="300.0"
+ auto:rotation="45.0" >
+ <path
+ auto:name="pie1"
+ auto:fillColor="#00000000"
+ auto:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ auto:strokeColor="#FF777777"
+ auto:strokeWidth="70"
+ auto:trimPathEnd=".75"
+ auto:trimPathOffset="0"
+ auto:trimPathStart="0" />
+ <path
+ auto:name="v"
+ auto:fillColor="#000000"
+ auto:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+
+ <group
+ auto:name="translateToCenterGroup"
+ auto:rotation="0.0"
+ auto:translateX="200.0"
+ auto:translateY="200.0" >
+ <group
+ auto:name="rotationGroup2"
+ auto:pivotX="0.0"
+ auto:pivotY="0.0"
+ auto:rotation="-45.0" >
+ <path
+ auto:name="twoLines1"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="translateGroupHalf"
+ auto:translateX="65.0"
+ auto:translateY="80.0" >
+ <group
+ auto:name="rotationGroup3"
+ auto:pivotX="-65.0"
+ auto:pivotY="-80.0"
+ auto:rotation="-45.0" >
+ <path
+ auto:name="twoLines2"
+ auto:fillColor="#FF00FF00"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="translateGroup"
+ auto:translateX="65.0"
+ auto:translateY="80.0" >
+ <group
+ auto:name="rotationGroupBlue"
+ auto:pivotX="-65.0"
+ auto:pivotY="-80.0"
+ auto:rotation="-45.0" >
+ <path
+ auto:name="twoLines3"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FF0000FF"
+ auto:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
new file mode 100644
index 0000000..43fc7ea
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
@@ -0,0 +1,38 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="600" >
+
+ <group>
+ <path
+ auto:name="pie1"
+ auto:fillColor="#ffffffff"
+ auto:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="1" />
+ <path
+ auto:name="half"
+ auto:fillColor="#FFFF0000"
+ auto:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ auto:strokeColor="#FF0000FF"
+ auto:strokeWidth="5" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
new file mode 100644
index 0000000..5b4fdd1
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
@@ -0,0 +1,39 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="500"
+ auto:viewportWidth="800" >
+
+ <group
+ auto:pivotX="90"
+ auto:pivotY="100"
+ auto:rotation="20">
+ <path
+ auto:name="pie2"
+ auto:pathData="M200,350 l 50,-25
+ a25,12 -30 0,1 100,-50 l 50,-25
+ a25,25 -30 0,1 100,-50 l 50,-25
+ a25,37 -30 0,1 100,-50 l 50,-25
+ a25,50 -30 0,1 100,-50 l 50,-25"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="10" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
new file mode 100644
index 0000000..f4ef87f
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
@@ -0,0 +1,35 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="500" >
+
+ <group
+ auto:pivotX="250"
+ auto:pivotY="200"
+ auto:rotation="180">
+ <path
+ auto:name="house"
+ auto:fillColor="#ff440000"
+ auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="10" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
new file mode 100644
index 0000000..0c64bca
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="200"
+ auto:viewportWidth="200" >
+
+ <group>
+ <path
+ auto:name="background1"
+ auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+ auto:fillColor="#FF000000"/>
+ <path
+ auto:name="background2"
+ auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+ auto:fillColor="#FF000000"/>
+ </group>
+ <group
+ auto:pivotX="100"
+ auto:pivotY="100"
+ auto:rotation="90"
+ auto:scaleX="0.75"
+ auto:scaleY="0.5"
+ auto:translateX="0.0"
+ auto:translateY="100.0">
+ <path
+ auto:name="twoLines"
+ auto:pathData="M 100,10 v 90 M 10,100 h 90"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="10" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
new file mode 100644
index 0000000..28cf09a
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
@@ -0,0 +1,30 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:width="64dp"
+ auto:height="64dp" auto:viewportWidth="1200"
+ auto:viewportHeight="600">
+
+ <group>
+ <path
+ auto:name="house"
+ auto:pathData="M200,300 Q400,50 600,300 T1000,300"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="10"/>
+ </group>
+
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
new file mode 100644
index 0000000..d66d4ff
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="500" >
+
+ <group>
+ <path
+ auto:name="house"
+ auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#FFFFFF00"
+ auto:strokeWidth="10" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
new file mode 100644
index 0000000..3a6559d
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
@@ -0,0 +1,34 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="800"
+ auto:viewportWidth="1000" >
+
+ <group>
+ <path
+ auto:name="house"
+ auto:pathData="M10,300 Q400,550 600,300 T1000,300"
+ auto:pivotX="90"
+ auto:pivotY="100"
+ auto:fillColor="#00000000"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="60" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
new file mode 100644
index 0000000..d6fd704
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
@@ -0,0 +1,35 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="480"
+ auto:viewportWidth="480" >
+
+ <group>
+ <path
+ auto:name="edit"
+ auto:fillColor="#FF00FFFF"
+ auto:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+ c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
+ c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
+ c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
+ auto:strokeColor="#FF000000"
+ auto:strokeWidth="10" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
new file mode 100644
index 0000000..9136b73
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="200"
+ auto:viewportWidth="200" >
+
+ <group>
+ <path
+ auto:name="background1"
+ auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+ auto:fillColor="#FF000000"/>
+ <path
+ auto:name="background2"
+ auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+ auto:fillColor="#FF000000"/>
+ </group>
+ <group
+ auto:pivotX="0"
+ auto:pivotY="0"
+ auto:rotation="90"
+ auto:scaleX="0.75"
+ auto:scaleY="0.5"
+ auto:translateX="100.0"
+ auto:translateY="100.0">
+ <path
+ auto:name="twoLines"
+ auto:pathData="M 100,10 v 90 M 10,100 h 90"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="10" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
new file mode 100644
index 0000000..2b33a89
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
@@ -0,0 +1,69 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="400" >
+
+ <group auto:name="backgroundGroup" >
+ <path
+ auto:name="background1"
+ auto:fillColor="#80000000"
+ auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ auto:name="background2"
+ auto:fillColor="#80000000"
+ auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ </group>
+ <group
+ auto:name="translateToCenterGroup"
+ auto:translateX="50.0"
+ auto:translateY="90.0" >
+ <path
+ auto:name="twoLines"
+ auto:pathData="M 0,0 v 100 M 0,0 h 100"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="rotationGroup"
+ auto:pivotX="0.0"
+ auto:pivotY="0.0"
+ auto:rotation="-45.0" >
+ <path
+ auto:name="twoLines1"
+ auto:pathData="M 0,0 v 100 M 0,0 h 100"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="translateGroup"
+ auto:translateX="130.0"
+ auto:translateY="160.0" >
+ <group auto:name="scaleGroup" >
+ <path
+ auto:name="twoLines2"
+ auto:pathData="M 0,0 v 100 M 0,0 h 100"
+ auto:strokeColor="#FF0000FF"
+ auto:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
new file mode 100644
index 0000000..d5759f9
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
@@ -0,0 +1,83 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="400" >
+
+ <group auto:name="backgroundGroup" >
+ <path
+ auto:name="background1"
+ auto:fillColor="#80000000"
+ auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ auto:name="background2"
+ auto:fillColor="#80000000"
+ auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ </group>
+ <group
+ auto:name="translateToCenterGroup"
+ auto:translateX="50.0"
+ auto:translateY="90.0" >
+ <path
+ auto:name="twoLines"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="rotationGroup"
+ auto:pivotX="0.0"
+ auto:pivotY="0.0"
+ auto:rotation="-45.0" >
+ <path
+ auto:name="twoLines1"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="translateGroup"
+ auto:translateX="130.0"
+ auto:translateY="160.0" >
+ <group auto:name="scaleGroup" >
+ <path
+ auto:name="twoLines3"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FF0000FF"
+ auto:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ auto:name="translateGroupHalf"
+ auto:translateX="65.0"
+ auto:translateY="80.0" >
+ <group auto:name="scaleGroup" >
+ <path
+ auto:name="twoLines2"
+ auto:pathData="@string/twoLinePathData"
+ auto:fillColor="#FFFFFFFF"
+ auto:strokeColor="#FFFFFFFF"
+ auto:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
new file mode 100644
index 0000000..b054692
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
@@ -0,0 +1,83 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="400" >
+
+ <group auto:name="backgroundGroup">
+ <path
+ auto:name="background1"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ <path
+ auto:name="background2"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ </group>
+ <group
+ auto:name="translateToCenterGroup"
+ auto:translateX="50.0"
+ auto:translateY="90.0" >
+ <path
+ auto:name="twoLines"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FFFF0000"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="rotationGroup"
+ auto:pivotX="0.0"
+ auto:pivotY="0.0"
+ auto:rotation="-45.0">
+ <path
+ auto:name="twoLines1"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeWidth="20" />
+
+ <group
+ auto:name="translateGroup"
+ auto:translateX="130.0"
+ auto:translateY="160.0">
+ <group auto:name="scaleGroup" >
+ <path
+ auto:name="twoLines3"
+ auto:pathData="@string/twoLinePathData"
+ auto:strokeColor="#FF0000FF"
+ auto:strokeWidth="20" />
+ </group>
+ </group>
+
+ <group
+ auto:name="translateGroupHalf"
+ auto:translateX="65.0"
+ auto:translateY="80.0">
+ <group auto:name="scaleGroup" >
+ <path
+ auto:name="twoLines2"
+ auto:pathData="@string/twoLinePathData"
+ auto:fillColor="#FFFFFFFF"
+ auto:strokeColor="#FFFFFFFF"
+ auto:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
new file mode 100644
index 0000000..7a94ed6
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
@@ -0,0 +1,83 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:width="64dp"
+ auto:viewportHeight="400"
+ auto:viewportWidth="400" >
+
+ <group
+ auto:name="FirstLevelGroup"
+ auto:translateX="100.0"
+ auto:translateY="0.0" >
+ <group
+ auto:name="SecondLevelGroup1"
+ auto:translateX="-100.0"
+ auto:translateY="50.0" >
+ <path
+ auto:fillColor="#FF00FF00"
+ auto:pathData="@string/rectangle200" />
+
+ <group
+ auto:name="ThridLevelGroup1"
+ auto:translateX="-100.0"
+ auto:translateY="50.0" >
+ <path
+ auto:fillColor="#FF0000FF"
+ auto:pathData="@string/rectangle200" />
+ </group>
+ <group
+ auto:name="ThridLevelGroup2"
+ auto:translateX="100.0"
+ auto:translateY="50.0" >
+ <path
+ auto:fillColor="#FF000000"
+ auto:pathData="@string/rectangle200" />
+ </group>
+ </group>
+ <group
+ auto:name="SecondLevelGroup2"
+ auto:translateX="100.0"
+ auto:translateY="50.0" >
+ <path
+ auto:fillColor="#FF0000FF"
+ auto:pathData="@string/rectangle200" />
+
+ <group
+ auto:name="ThridLevelGroup3"
+ auto:translateX="-100.0"
+ auto:translateY="50.0" >
+ <path
+ auto:fillColor="#FFFF0000"
+ auto:pathData="@string/rectangle200" />
+ </group>
+ <group
+ auto:name="ThridLevelGroup4"
+ auto:translateX="100.0"
+ auto:translateY="50.0" >
+ <path
+ auto:fillColor="#FF00FF00"
+ auto:pathData="@string/rectangle200" />
+ </group>
+ </group>
+
+ <path
+ auto:fillColor="#FFFF0000"
+ auto:pathData="@string/rectangle200" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
new file mode 100644
index 0000000..b2dd4a3
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:viewportHeight="200"
+ auto:viewportWidth="200"
+ auto:width="64dp" >
+
+ <group>
+ <path
+ auto:name="background1"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ auto:name="background2"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ auto:translateX="50"
+ auto:translateY="50" >
+ <path
+ auto:name="twoLines"
+ auto:pathData="M 100,20 l 0 80 l -30 -80"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeLineCap="butt"
+ auto:strokeLineJoin="miter"
+ auto:strokeMiterLimit="5"
+ auto:strokeWidth="20" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
new file mode 100644
index 0000000..b8f88ce
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
@@ -0,0 +1,46 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:viewportHeight="200"
+ auto:viewportWidth="200"
+ auto:width="64dp" >
+
+ <group>
+ <path
+ auto:name="background1"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ auto:name="background2"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ auto:translateX="50"
+ auto:translateY="50" >
+ <path
+ auto:name="twoLines"
+ auto:pathData="M 100,20 l 0 80 l -30 -80"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeLineCap="round"
+ auto:strokeLineJoin="round"
+ auto:strokeMiterLimit="10"
+ auto:strokeWidth="20" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
new file mode 100644
index 0000000..30c7fce
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
@@ -0,0 +1,47 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="64dp"
+ auto:viewportHeight="200"
+ auto:viewportWidth="200"
+ auto:width="64dp"
+ auto:autoMirrored="true" >
+
+ <group>
+ <path
+ auto:name="background1"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ auto:name="background2"
+ auto:fillColor="#FF000000"
+ auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ auto:translateX="50"
+ auto:translateY="50" >
+ <path
+ auto:name="twoLines"
+ auto:pathData="M 100,20 l 0 80 l -30 -80"
+ auto:strokeColor="#FF00FF00"
+ auto:strokeLineCap="square"
+ auto:strokeLineJoin="bevel"
+ auto:strokeMiterLimit="10"
+ auto:strokeWidth="20" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
new file mode 100644
index 0000000..2ac1d42
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="48dp"
+ auto:width="48dp"
+ auto:viewportHeight="1"
+ auto:viewportWidth="1" >
+
+ <group>
+ <path
+ auto:name="box1"
+ auto:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
+ auto:fillColor="#ff00ff00"/>
+ </group>
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
new file mode 100644
index 0000000..6abb455
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ auto:height="48dp"
+ auto:width="48dp"
+ auto:viewportHeight="48"
+ auto:viewportWidth="48" >
+
+ <group>
+ <path
+ auto:name="plus1"
+ auto:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
+ auto:fillColor="#ff00ff00"/>
+ </group>
+</vector>
diff --git a/graphics/drawable/teststatic/res/raw/vector_drawable01.xml b/graphics/drawable/teststatic/res/raw/vector_drawable01.xml
new file mode 100644
index 0000000..baa3fc7
--- /dev/null
+++ b/graphics/drawable/teststatic/res/raw/vector_drawable01.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:auto="http://schemas.android.com/apk/res-auto"
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="480"
+ android:viewportWidth="480" >
+
+ <group>
+ <path
+ android:name="box1"
+ android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
+ android:fillColor="?android:attr/colorControlActivated"
+ android:strokeColor="?android:attr/colorControlActivated"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round" />
+ </group>
+</vector>
diff --git a/graphics/drawable/teststatic/res/values/strings.xml b/graphics/drawable/teststatic/res/values/strings.xml
new file mode 100644
index 0000000..c5451c8
--- /dev/null
+++ b/graphics/drawable/teststatic/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="twoLinePathData">"M 0,0 v 100 M 0,0 h 100"</string>
+ <string name="triangle"> "M300,70 l 0,-70 70,70 0,0 -70,70z"</string>
+ <string name="rectangle">"M300,70 l 0,-70 70,0 0,140 -70,0 z"</string>
+ <string name="rectangle2">"M300,70 l 0,-70 70,0 0,70z M300,70 l 70,0 0,70 -70,0z"</string>
+ <string name="equal2"> "M300,35 l 0,-35 70,0 0,35z M300,105 l 70,0 0,35 -70,0z"</string>
+ <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string>
+ <string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string>
+ <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
+</resources>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
new file mode 100644
index 0000000..8bb766e
--- /dev/null
+++ b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.test.vectordrawable;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.os.Bundle;
+import android.support.graphics.drawable.VectorDrawableCompat;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.text.DecimalFormat;
+
+public class TestActivity extends Activity {
+ private static final String LOG_TAG = "TestActivity";
+
+ private static final String LOGCAT = "VectorDrawable1";
+ protected int[] icon = {
+ R.drawable.vector_drawable01,
+ R.drawable.vector_drawable02,
+ R.drawable.vector_drawable03,
+ R.drawable.vector_drawable04,
+ R.drawable.vector_drawable05,
+ R.drawable.vector_drawable06,
+ R.drawable.vector_drawable07,
+ R.drawable.vector_drawable08,
+ R.drawable.vector_drawable09,
+ R.drawable.vector_drawable10,
+ R.drawable.vector_drawable11,
+ R.drawable.vector_drawable12,
+ R.drawable.vector_drawable13,
+ R.drawable.vector_drawable14,
+ R.drawable.vector_drawable15,
+ R.drawable.vector_drawable16,
+ R.drawable.vector_drawable17,
+ R.drawable.vector_drawable18,
+ R.drawable.vector_drawable19,
+ R.drawable.vector_drawable20,
+ R.drawable.vector_drawable21,
+ R.drawable.vector_drawable22,
+ R.drawable.vector_drawable23,
+ R.drawable.vector_drawable24,
+ R.drawable.vector_drawable25,
+ R.drawable.vector_drawable26,
+ R.drawable.vector_drawable27,
+ R.drawable.vector_drawable28,
+ R.drawable.vector_drawable29,
+ R.drawable.vector_drawable30,
+ };
+
+ private static final int EXTRA_TESTS = 2;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ScrollView scrollView = new ScrollView(this);
+ LinearLayout container = new LinearLayout(this);
+ scrollView.addView(container);
+ container.setOrientation(LinearLayout.VERTICAL);
+ Resources res = this.getResources();
+ container.setBackgroundColor(0xFF888888);
+ VectorDrawableCompat []d = new VectorDrawableCompat[icon.length];
+ long time = android.os.SystemClock.currentThreadTimeMillis();
+ for (int i = 0; i < icon.length; i++) {
+ d[i] = VectorDrawableCompat.create(res, icon[i], getTheme());
+ }
+ time = android.os.SystemClock.currentThreadTimeMillis()-time;
+
+ // Testing Tint on one particular case.
+ d[3].setTint(0x8000FF00);
+ d[3].setTintMode(Mode.MULTIPLY);
+
+ // Testing Constant State like operation by creating the first 2 icons
+ // from the 3rd one's constant state.
+ VectorDrawableCompat []extras = new VectorDrawableCompat[EXTRA_TESTS];
+ ConstantState state = d[0].getConstantState();
+ extras[0] = (VectorDrawableCompat) state.newDrawable();
+ extras[1] = (VectorDrawableCompat) state.newDrawable();
+
+ // This alpha change is expected to affect both extra 0, 1, and d0.
+ extras[0].setAlpha(128);
+
+ d[0].mutate();
+ d[0].setAlpha(255);
+
+ // Just show the average create time as the first view.
+ TextView t = new TextView(this);
+ DecimalFormat df = new DecimalFormat("#.##");
+ t.setText("avgL=" + df.format(time / (icon.length)) + " ms");
+ container.addView(t);
+
+ addDrawableButtons(container, extras);
+
+ addDrawableButtons(container, d);
+
+ setContentView(scrollView);
+ }
+
+ private void addDrawableButtons(LinearLayout container, VectorDrawableCompat[] d) {
+ // Add the VD into consequent views.
+ for (int i = 0; i < d.length; i++) {
+ Button button = new Button(this);
+ button.setWidth(200);
+ // Note that setBackgroundResource() will fail b/c createFromXmlInner() failed
+ // to recognize <vector> pre-L.
+ button.setBackgroundDrawable(d[i]);
+ container.addView(button);
+ }
+ }
+}
diff --git a/percent/src/android/support/percent/PercentFrameLayout.java b/percent/src/android/support/percent/PercentFrameLayout.java
index 994be4c..90c238d 100644
--- a/percent/src/android/support/percent/PercentFrameLayout.java
+++ b/percent/src/android/support/percent/PercentFrameLayout.java
@@ -134,6 +134,10 @@
@Override
public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
+ if (mPercentLayoutInfo == null) {
+ mPercentLayoutInfo = new PercentLayoutHelper.PercentLayoutInfo();
+ }
+
return mPercentLayoutInfo;
}
diff --git a/percent/src/android/support/percent/PercentRelativeLayout.java b/percent/src/android/support/percent/PercentRelativeLayout.java
index 1a06b8d..07c08cf 100644
--- a/percent/src/android/support/percent/PercentRelativeLayout.java
+++ b/percent/src/android/support/percent/PercentRelativeLayout.java
@@ -120,6 +120,10 @@
@Override
public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
+ if (mPercentLayoutInfo == null) {
+ mPercentLayoutInfo = new PercentLayoutHelper.PercentLayoutInfo();
+ }
+
return mPercentLayoutInfo;
}
diff --git a/previewsdk/Android.mk b/previewsdk/Android.mk
new file mode 100644
index 0000000..95f5dba
--- /dev/null
+++ b/previewsdk/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Here is the final static library that apps can link against.
+include $(CLEAR_VARS)
+
+previewsdk_generate_constants_exe := $(LOCAL_PATH)/previewconstants.sh
+previewsdk_gen_java_files := $(TARGET_OUT_COMMON_GEN)/previewsdk/PreviewSdkConstants.java
+
+$(previewsdk_gen_java_files): $(previewsdk_generate_constants_exe)
+ $(hide) mkdir -p $(dir $@)
+ $(hide) PLATFORM_PREVIEW_SDK_VERSION="$(PLATFORM_PREVIEW_SDK_VERSION)" \
+ bash $< > $@
+
+LOCAL_MODULE := android-support-previewsdk
+LOCAL_SDK_VERSION := current
+LOCAL_GENERATED_SOURCES := $(previewsdk_gen_java_files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/previewsdk/previewconstants.sh b/previewsdk/previewconstants.sh
new file mode 100755
index 0000000..de94f84
--- /dev/null
+++ b/previewsdk/previewconstants.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+echo "/** Begin preview constants"
+echo " * autogenerated by previewconstants.sh */"
+echo "package android.support.previewsdk;"
+echo "class PreviewConstants {"
+echo " public static final int PREVIEW_SDK_VERSION = $PLATFORM_PREVIEW_SDK_VERSION;"
+echo "}"
diff --git a/previewsdk/src/android/support/previewsdk/PreviewSdk.java b/previewsdk/src/android/support/previewsdk/PreviewSdk.java
new file mode 100644
index 0000000..8b494c7
--- /dev/null
+++ b/previewsdk/src/android/support/previewsdk/PreviewSdk.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.previewsdk;
+
+import android.os.Build;
+
+/**
+ * Utility class for performing version checks on Android platform preview SDKs.
+ *
+ * <p>Apps must be very careful when targeting preview builds because binary compatibility
+ * is not guaranteed. APIs can be renamed or drastically changed before they are finalized
+ * into a new API level. The new SDK constant <code>Build.VERSION.PREVIEW_SDK_INT</code>
+ * marks a precise snapshot version of prerelease API.</p>
+ *
+ * <p>{@link #isKnownPreviewDevice()} will return <code>true</code> if the current device
+ * is running a preview build with the same SDK snapshot this support lib was built with.
+ * If it returns <code>true</code> it is safe to call prerelease APIs. If not, the app
+ * should fall back to only assuming the presence of the latest public, final API level.</p>
+ */
+public class PreviewSdk {
+ /**
+ * Check if the current device is running a prerelease platform preview build matching
+ * the SDK this library was built for. If it returns true, it is safe to call prerelease
+ * APIs known to this SDK.
+ *
+ * @return true if the device is running a preview build that matches the SDK.
+ */
+ public static boolean isKnownPreviewDevice() {
+ return "MNC".equals(Build.VERSION.CODENAME)
+ && Build.VERSION.PREVIEW_SDK_INT == PreviewConstants.PREVIEW_SDK_VERSION;
+ }
+}
diff --git a/recommendation/Android.mk b/recommendation/Android.mk
new file mode 100644
index 0000000..3d8edf8
--- /dev/null
+++ b/recommendation/Android.mk
@@ -0,0 +1,60 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := 21
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+
+LOCAL_JAVA_LIBRARIES := \
+ android-support-v4
+
+LOCAL_MODULE := android-support-recommendation
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# ===========================================================
+# Common Droiddoc vars
+recommendation.docs.src_files := \
+ $(call all-java-files-under, src) \
+ $(call all-html-files-under, src)
+recommendation.docs.java_libraries := \
+ framework \
+ android-support-v4 \
+ android-support-recommendation
+
+# Documentation
+# ===========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android-support-recommendation
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(recommendation.docs.src_files)
+
+LOCAL_SDK_VERSION := 21
+LOCAL_IS_HOST_MODULE := false
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := build/tools/droiddoc/templates-sdk
+
+LOCAL_JAVA_LIBRARIES := $(recommendation.docs.java_libraries)
+
+LOCAL_DROIDDOC_OPTIONS := \
+ -offlinemode \
+ -hdf android.whichdoc offline \
+ -federate Android http://developer.android.com \
+ -federationapi Android prebuilts/sdk/api/21.txt \
+ -hide 113
+
+include $(BUILD_DROIDDOC)
+
+
+# API Check
+# ---------------------------------------------
+support_module := $(LOCAL_MODULE)
+support_module_api_dir := $(LOCAL_PATH)/api
+support_module_src_files := $(recommendation.docs.src_files)
+support_module_java_libraries := $(recommendation.docs.java_libraries)
+support_module_java_packages := android.support.app.recommendation*
+include $(SUPPORT_API_CHECK)
diff --git a/recommendation/AndroidManifest.xml b/recommendation/AndroidManifest.xml
new file mode 100644
index 0000000..ef1223e
--- /dev/null
+++ b/recommendation/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.recommendation">
+ <uses-sdk android:minSdkVersion="21"/>
+ <application />
+</manifest>
diff --git a/recommendation/api/current.txt b/recommendation/api/current.txt
new file mode 100644
index 0000000..ce69b31
--- /dev/null
+++ b/recommendation/api/current.txt
@@ -0,0 +1,132 @@
+package android.support.app.recommendation {
+
+ public final class ContentRecommendation {
+ method public java.lang.String getBackgroundImageUri();
+ method public int getBadgeImageResourceId();
+ method public int getColor();
+ method public android.graphics.Bitmap getContentImage();
+ method public android.support.app.recommendation.ContentRecommendation.IntentData getContentIntent();
+ method public java.lang.String[] getContentTypes();
+ method public android.support.app.recommendation.ContentRecommendation.IntentData getDismissIntent();
+ method public java.lang.String[] getGenres();
+ method public java.lang.String getGroup();
+ method public java.lang.String getIdTag();
+ method public java.lang.String getMaturityRating();
+ method public android.app.Notification getNotificationObject(android.content.Context);
+ method public java.lang.String getPricingType();
+ method public java.lang.String getPricingValue();
+ method public java.lang.String getPrimaryContentType();
+ method public int getProgressMax();
+ method public int getProgressValue();
+ method public long getRunningTime();
+ method public java.lang.String getSortKey();
+ method public java.lang.String getSourceName();
+ method public int getStatus();
+ method public java.lang.String getText();
+ method public java.lang.String getTitle();
+ method public boolean hasProgressInfo();
+ method public boolean isAutoDismiss();
+ method public void setAutoDismiss(boolean);
+ method public void setGroup(java.lang.String);
+ method public void setProgress(int, int);
+ method public void setSortKey(java.lang.String);
+ method public void setStatus(int);
+ field public static final java.lang.String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
+ field public static final java.lang.String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
+ field public static final java.lang.String CONTENT_MATURITY_LOW = "android.contentMaturity.low";
+ field public static final java.lang.String CONTENT_MATURITY_MEDIUM = "android.contentMaturity.medium";
+ field public static final java.lang.String CONTENT_PRICING_FREE = "android.contentPrice.free";
+ field public static final java.lang.String CONTENT_PRICING_PREORDER = "android.contentPrice.preorder";
+ field public static final java.lang.String CONTENT_PRICING_PURCHASE = "android.contentPrice.purchase";
+ field public static final java.lang.String CONTENT_PRICING_RENTAL = "android.contentPrice.rental";
+ field public static final java.lang.String CONTENT_PRICING_SUBSCRIPTION = "android.contentPrice.subscription";
+ field public static final int CONTENT_STATUS_AVAILABLE = 2; // 0x2
+ field public static final int CONTENT_STATUS_PENDING = 1; // 0x1
+ field public static final int CONTENT_STATUS_READY = 0; // 0x0
+ field public static final int CONTENT_STATUS_UNAVAILABLE = 3; // 0x3
+ field public static final java.lang.String CONTENT_TYPE_APP = "android.contentType.app";
+ field public static final java.lang.String CONTENT_TYPE_BOOK = "android.contentType.book";
+ field public static final java.lang.String CONTENT_TYPE_COMIC = "android.contentType.comic";
+ field public static final java.lang.String CONTENT_TYPE_GAME = "android.contentType.game";
+ field public static final java.lang.String CONTENT_TYPE_MAGAZINE = "android.contentType.magazine";
+ field public static final java.lang.String CONTENT_TYPE_MOVIE = "android.contentType.movie";
+ field public static final java.lang.String CONTENT_TYPE_MUSIC = "android.contentType.music";
+ field public static final java.lang.String CONTENT_TYPE_NEWS = "android.contentType.news";
+ field public static final java.lang.String CONTENT_TYPE_PODCAST = "android.contentType.podcast";
+ field public static final java.lang.String CONTENT_TYPE_RADIO = "android.contentType.radio";
+ field public static final java.lang.String CONTENT_TYPE_SERIAL = "android.contentType.serial";
+ field public static final java.lang.String CONTENT_TYPE_SPORTS = "android.contentType.sports";
+ field public static final java.lang.String CONTENT_TYPE_TRAILER = "android.contentType.trailer";
+ field public static final java.lang.String CONTENT_TYPE_VIDEO = "android.contentType.video";
+ field public static final java.lang.String CONTENT_TYPE_WEBSITE = "android.contentType.website";
+ field public static final int INTENT_TYPE_ACTIVITY = 1; // 0x1
+ field public static final int INTENT_TYPE_BROADCAST = 2; // 0x2
+ field public static final int INTENT_TYPE_SERVICE = 3; // 0x3
+ }
+
+ public static final class ContentRecommendation.Builder {
+ ctor public ContentRecommendation.Builder();
+ method public android.support.app.recommendation.ContentRecommendation build();
+ method public android.support.app.recommendation.ContentRecommendation.Builder setAutoDismiss(boolean);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setBackgroundImageUri(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setBadgeIcon(int);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setColor(int);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setContentImage(android.graphics.Bitmap);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setContentIntentData(int, android.content.Intent, int, android.os.Bundle);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setContentTypes(java.lang.String[]);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setDismissIntentData(int, android.content.Intent, int, android.os.Bundle);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setGenres(java.lang.String[]);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setGroup(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setIdTag(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setMaturityRating(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setPricingInformation(java.lang.String, java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setProgress(int, int);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setRunningTime(long);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setSortKey(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setSourceName(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setStatus(int);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setText(java.lang.String);
+ method public android.support.app.recommendation.ContentRecommendation.Builder setTitle(java.lang.String);
+ }
+
+ public static abstract class ContentRecommendation.ContentMaturity implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class ContentRecommendation.ContentPricing implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class ContentRecommendation.ContentStatus implements java.lang.annotation.Annotation {
+ }
+
+ public static abstract class ContentRecommendation.ContentType implements java.lang.annotation.Annotation {
+ }
+
+ public static class ContentRecommendation.IntentData {
+ ctor public ContentRecommendation.IntentData();
+ }
+
+ public static abstract class ContentRecommendation.IntentType implements java.lang.annotation.Annotation {
+ }
+
+ public final class RecommendationExtender implements android.app.Notification.Extender {
+ ctor public RecommendationExtender();
+ ctor public RecommendationExtender(android.app.Notification);
+ method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+ method public java.lang.String[] getContentTypes();
+ method public java.lang.String[] getGenres();
+ method public java.lang.String getMaturityRating();
+ method public java.lang.String getPricingType();
+ method public java.lang.String getPricingValue();
+ method public java.lang.String getPrimaryContentType();
+ method public long getRunningTime();
+ method public int getStatus();
+ method public android.support.app.recommendation.RecommendationExtender setContentTypes(java.lang.String[]);
+ method public android.support.app.recommendation.RecommendationExtender setGenres(java.lang.String[]);
+ method public android.support.app.recommendation.RecommendationExtender setMaturityRating(java.lang.String);
+ method public android.support.app.recommendation.RecommendationExtender setPricingInformation(java.lang.String, java.lang.String);
+ method public android.support.app.recommendation.RecommendationExtender setRunningTime(long);
+ method public android.support.app.recommendation.RecommendationExtender setStatus(int);
+ }
+
+}
+
diff --git a/recommendation/api/removed.txt b/recommendation/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/recommendation/api/removed.txt
diff --git a/recommendation/src/android/support/app/recommendation/ContentRecommendation.java b/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
new file mode 100644
index 0000000..fdc0907
--- /dev/null
+++ b/recommendation/src/android/support/app/recommendation/ContentRecommendation.java
@@ -0,0 +1,1153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.app.recommendation;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringDef;
+import android.text.TextUtils;
+
+import java.util.Arrays;
+
+/**
+ * The ContentRecommendation object encapsulates all application provided data for a single content
+ * recommendation item.
+ */
+public final class ContentRecommendation
+{
+ @StringDef({
+ CONTENT_TYPE_VIDEO,
+ CONTENT_TYPE_MOVIE,
+ CONTENT_TYPE_TRAILER,
+ CONTENT_TYPE_SERIAL,
+ CONTENT_TYPE_MUSIC,
+ CONTENT_TYPE_RADIO,
+ CONTENT_TYPE_PODCAST,
+ CONTENT_TYPE_NEWS,
+ CONTENT_TYPE_SPORTS,
+ CONTENT_TYPE_APP,
+ CONTENT_TYPE_GAME,
+ CONTENT_TYPE_BOOK,
+ CONTENT_TYPE_COMIC,
+ CONTENT_TYPE_MAGAZINE,
+ CONTENT_TYPE_WEBSITE,
+ })
+ public @interface ContentType {}
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a video clip.
+ */
+ public static final String CONTENT_TYPE_VIDEO = "android.contentType.video";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a movie.
+ */
+ public static final String CONTENT_TYPE_MOVIE = "android.contentType.movie";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a trailer.
+ */
+ public static final String CONTENT_TYPE_TRAILER = "android.contentType.trailer";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is serial. It can refer to an entire show, a single season or
+ * series, or a single episode.
+ */
+ public static final String CONTENT_TYPE_SERIAL = "android.contentType.serial";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a song or album.
+ */
+ public static final String CONTENT_TYPE_MUSIC = "android.contentType.music";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a radio station.
+ */
+ public static final String CONTENT_TYPE_RADIO = "android.contentType.radio";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a podcast.
+ */
+ public static final String CONTENT_TYPE_PODCAST = "android.contentType.podcast";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a news item.
+ */
+ public static final String CONTENT_TYPE_NEWS = "android.contentType.news";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is sports.
+ */
+ public static final String CONTENT_TYPE_SPORTS = "android.contentType.sports";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is an application.
+ */
+ public static final String CONTENT_TYPE_APP = "android.contentType.app";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a game.
+ */
+ public static final String CONTENT_TYPE_GAME = "android.contentType.game";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a book.
+ */
+ public static final String CONTENT_TYPE_BOOK = "android.contentType.book";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a comic book.
+ */
+ public static final String CONTENT_TYPE_COMIC = "android.contentType.comic";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a magazine.
+ */
+ public static final String CONTENT_TYPE_MAGAZINE = "android.contentType.magazine";
+
+ /**
+ * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred
+ * by the notification item is a website.
+ */
+ public static final String CONTENT_TYPE_WEBSITE = "android.contentType.website";
+
+ @StringDef({
+ CONTENT_PRICING_FREE,
+ CONTENT_PRICING_RENTAL,
+ CONTENT_PRICING_PURCHASE,
+ CONTENT_PRICING_PREORDER,
+ CONTENT_PRICING_SUBSCRIPTION,
+ })
+ public @interface ContentPricing {}
+
+ /**
+ * Value to be used with {@link Builder#setPricingInformation} to indicate that the content
+ * referred by the notification item is free to consume.
+ */
+ public static final String CONTENT_PRICING_FREE = "android.contentPrice.free";
+
+ /**
+ * Value to be used with {@link Builder#setPricingInformation} to indicate that the content
+ * referred by the notification item is available as a rental, and the price value provided is
+ * the rental price for the item.
+ */
+ public static final String CONTENT_PRICING_RENTAL = "android.contentPrice.rental";
+
+ /**
+ * Value to be used with {@link Builder#setPricingInformation} to indicate that the content
+ * referred by the notification item is available for purchase, and the price value provided is
+ * the purchase price for the item.
+ */
+ public static final String CONTENT_PRICING_PURCHASE = "android.contentPrice.purchase";
+
+ /**
+ * Value to be used with {@link Builder#setPricingInformation} to indicate that the content
+ * referred by the notification item is available currently as a pre-order, and the price value
+ * provided is the purchase price for the item.
+ */
+ public static final String CONTENT_PRICING_PREORDER = "android.contentPrice.preorder";
+
+ /**
+ * Value to be used with {@link Builder#setPricingInformation} to indicate that the content
+ * referred by the notification item is available as part of a subscription based service, and
+ * the price value provided is the subscription price for the service.
+ */
+ public static final String CONTENT_PRICING_SUBSCRIPTION =
+ "android.contentPrice.subscription";
+
+ @IntDef({
+ CONTENT_STATUS_READY,
+ CONTENT_STATUS_PENDING,
+ CONTENT_STATUS_AVAILABLE,
+ CONTENT_STATUS_UNAVAILABLE,
+ })
+ public @interface ContentStatus {}
+
+ /**
+ * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the
+ * notification is available and ready to be consumed immediately.
+ */
+ public static final int CONTENT_STATUS_READY = 0;
+
+ /**
+ * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the
+ * notification is pending, waiting on either a download or purchase operation to complete
+ * before it can be consumed.
+ */
+ public static final int CONTENT_STATUS_PENDING = 1;
+
+ /**
+ * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the
+ * notification is available, but needs to be first purchased, rented, subscribed or downloaded
+ * before it can be consumed.
+ */
+ public static final int CONTENT_STATUS_AVAILABLE = 2;
+
+ /**
+ * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the
+ * notification is not available. This could be content not available in a certain region or
+ * incompatible with the device in use.
+ */
+ public static final int CONTENT_STATUS_UNAVAILABLE = 3;
+
+ @StringDef({
+ CONTENT_MATURITY_ALL,
+ CONTENT_MATURITY_LOW,
+ CONTENT_MATURITY_MEDIUM,
+ CONTENT_MATURITY_HIGH,
+ })
+ public @interface ContentMaturity {}
+
+ /**
+ * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred
+ * by the notification is suitable for all audiences.
+ */
+ public static final String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
+
+ /**
+ * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred
+ * by the notification is suitable for audiences of low maturity and above.
+ */
+ public static final String CONTENT_MATURITY_LOW = "android.contentMaturity.low";
+
+ /**
+ * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred
+ * by the notification is suitable for audiences of medium maturity and above.
+ */
+ public static final String CONTENT_MATURITY_MEDIUM = "android.contentMaturity.medium";
+
+ /**
+ * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred
+ * by the notification is suitable for audiences of high maturity and above.
+ */
+ public static final String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
+
+ @IntDef({
+ INTENT_TYPE_ACTIVITY,
+ INTENT_TYPE_BROADCAST,
+ INTENT_TYPE_SERVICE,
+ })
+ public @interface IntentType {
+ }
+
+ /**
+ * Value to be used with {@link Builder#setContentIntentData} and
+ * {@link Builder#setDismissIntentData} to indicate that a {@link PendingIntent} for an Activity
+ * should be created when posting the recommendation to the HomeScreen.
+ */
+ public static final int INTENT_TYPE_ACTIVITY = 1;
+
+ /**
+ * Value to be used with {@link Builder#setContentIntentData} and
+ * {@link Builder#setDismissIntentData} to indicate that a {@link PendingIntent} for a Broadcast
+ * should be created when posting the recommendation to the HomeScreen.
+ */
+ public static final int INTENT_TYPE_BROADCAST = 2;
+
+ /**
+ * Value to be used with {@link Builder#setContentIntentData} and
+ * {@link Builder#setDismissIntentData} to indicate that a {@link PendingIntent} for a Service
+ * should be created when posting the recommendation to the HomeScreen.
+ */
+ public static final int INTENT_TYPE_SERVICE = 3;
+
+ /**
+ * Object used to encapsulate the data to be used to build the {@link PendingIntent} object
+ * associated with a given content recommendation, at the time this recommendation gets posted
+ * to the home Screen.
+ * <p>
+ * The members of this object correspond to the fields passed into the {@link PendingIntent}
+ * factory methods, when creating a new PendingIntent.
+ */
+ public static class IntentData {
+ int mType;
+ Intent mIntent;
+ int mRequestCode;
+ Bundle mOptions;
+ }
+
+ private final String mIdTag;
+ private final String mTitle;
+ private final String mText;
+ private final String mSourceName;
+ private final Bitmap mContentImage;
+ private final int mBadgeIconId;
+ private final String mBackgroundImageUri;
+ private final int mColor;
+ private final IntentData mContentIntentData;
+ private final IntentData mDismissIntentData;
+ private final String[] mContentTypes;
+ private final String[] mContentGenres;
+ private final String mPriceType;
+ private final String mPriceValue;
+ private final String mMaturityRating;
+ private final long mRunningTime;
+
+ // Mutable fields
+ private String mGroup;
+ private String mSortKey;
+ private int mProgressAmount;
+ private int mProgressMax;
+ private boolean mAutoDismiss;
+ private int mStatus;
+
+ private ContentRecommendation(Builder builder) {
+ mIdTag = builder.mBuilderIdTag;
+ mTitle = builder.mBuilderTitle;
+ mText = builder.mBuilderText;
+ mSourceName = builder.mBuilderSourceName;
+ mContentImage = builder.mBuilderContentImage;
+ mBadgeIconId = builder.mBuilderBadgeIconId;
+ mBackgroundImageUri = builder.mBuilderBackgroundImageUri;
+ mColor = builder.mBuilderColor;
+ mContentIntentData = builder.mBuilderContentIntentData;
+ mDismissIntentData = builder.mBuilderDismissIntentData;
+ mContentTypes = builder.mBuilderContentTypes;
+ mContentGenres = builder.mBuilderContentGenres;
+ mPriceType = builder.mBuilderPriceType;
+ mPriceValue = builder.mBuilderPriceValue;
+ mMaturityRating = builder.mBuilderMaturityRating;
+ mRunningTime = builder.mBuilderRunningTime;
+
+ mGroup = builder.mBuilderGroup;
+ mSortKey = builder.mBuilderSortKey;
+ mProgressAmount = builder.mBuilderProgressAmount;
+ mProgressMax = builder.mBuilderProgressMax;
+ mAutoDismiss = builder.mBuilderAutoDismiss;
+ mStatus = builder.mBuilderStatus;
+ }
+
+ /**
+ * Returns the String Id tag which uniquely identifies this recommendation.
+ *
+ * @return The String Id tag for this recommendation.
+ */
+ public String getIdTag() {
+ return mIdTag;
+ }
+
+ /**
+ * Returns the content title for this recommendation.
+ *
+ * @return A String containing the recommendation content title.
+ */
+ public String getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Returns the description text for this recommendation.
+ *
+ * @return A String containing the recommendation description text.
+ */
+ public String getText() {
+ return mText;
+ }
+
+ /**
+ * Returns the source application name for this recommendation.
+ *
+ * @return A String containing the recommendation source name.
+ */
+ public String getSourceName() {
+ return mSourceName;
+ }
+
+ /**
+ * Returns the Bitmap containing the recommendation image.
+ *
+ * @return A Bitmap containing the recommendation image.
+ */
+ public Bitmap getContentImage() {
+ return mContentImage;
+ }
+
+ /**
+ * Returns the resource id for the recommendation badging icon.
+ * <p>
+ * The resource id represents the icon resource in the source application package.
+ *
+ * @return An integer id for the badge icon resource.
+ */
+ public int getBadgeImageResourceId() {
+ return mBadgeIconId;
+ }
+
+ /**
+ * Returns a Content URI that can be used to retrieve the background image for this
+ * recommendation.
+ *
+ * @return A Content URI pointing to the recommendation background image.
+ */
+ public String getBackgroundImageUri() {
+ return mBackgroundImageUri;
+ }
+
+ /**
+ * Returns the accent color value to be used in the UI when displaying this content
+ * recommendation to the user.
+ *
+ * @return An integer value representing the accent color for this recommendation.
+ */
+ public int getColor() {
+ return mColor;
+ }
+
+ /**
+ * Sets the String group ID tag for this recommendation.
+ * <p>
+ * Recommendations in the same group are ranked by the Home Screen together, and the sort order
+ * within a group is respected. This can be useful if the application has different sources for
+ * recommendations, like "trending", "subscriptions", and "new music" categories for YouTube,
+ * where the user can be more interested in recommendations from one group than another.
+ *
+ * @param groupTag A String containing the group ID tag for this recommendation.
+ */
+ public void setGroup(String groupTag) {
+ mGroup = groupTag;
+ }
+
+ /**
+ * Returns the String group ID tag for this recommendation.
+ *
+ * @return A String containing the group ID tag for this recommendation.
+ */
+ public String getGroup() {
+ return mGroup;
+ }
+
+ /**
+ * Sets the String sort key for this recommendation.
+ * <p>
+ * The sort key must be a String representation of a float number between 0.0 and 1.0, and is
+ * used to indicate the relative importance (and sort order) of a single recommendation within
+ * its specified group. The recommendations will be ordered in decreasing order of importance
+ * within a given group.
+ *
+ * @param sortKey A String containing the sort key for this recommendation.
+ */
+ public void setSortKey(String sortKey) {
+ mSortKey = sortKey;
+ }
+
+ /**
+ * Returns the String sort key for this recommendation.
+ *
+ * @return A String containing the sort key for this recommendation.
+ */
+ public String getSortKey() {
+ return mSortKey;
+ }
+
+ /**
+ * Sets the progress information for the content pointed to by this recommendation.
+ *
+ * @param max The maximum value for the progress of this content.
+ * @param progress The progress amount for this content. Must be in the range (0 - max).
+ */
+ public void setProgress(int max, int progress) {
+ if (max < 0 || progress < 0) {
+ throw new IllegalArgumentException();
+ }
+ mProgressMax = max;
+ mProgressAmount = progress;
+ }
+
+ /**
+ * Indicates if this recommendation contains valid progress information.
+ *
+ * @return true if the recommendation contains valid progress data, false otherwise.
+ */
+ public boolean hasProgressInfo() {
+ return mProgressMax != 0;
+ }
+
+ /**
+ * Returns the maximum value for the progress data of this recommendation.
+ *
+ * @return An integer representing the maximum progress value.
+ */
+ public int getProgressMax() {
+ return mProgressMax;
+ }
+
+ /**
+ * Returns the progress amount for this recommendation.
+ *
+ * @return An integer representing the recommendation progress amount.
+ */
+ public int getProgressValue() {
+ return mProgressAmount;
+ }
+
+ /**
+ * Sets the flag indicating if this recommendation should be dismissed automatically.
+ * <p>
+ * Auto-dismiss notifications are automatically removed from the Home Screen when the user
+ * clicks on them.
+ *
+ * @param autoDismiss A boolean indicating if the recommendation should be auto dismissed or
+ * not.
+ */
+ public void setAutoDismiss(boolean autoDismiss) {
+ mAutoDismiss = autoDismiss;
+ }
+
+ /**
+ * Indicates whether this recommendation should be dismissed automatically.
+ * <p>
+ * Auto-dismiss notifications are automatically removed from the Home Screen when the user
+ * clicks on them.
+ *
+ * @return true if the recommendation is marked for auto dismissal, or false otherwise.
+ */
+ public boolean isAutoDismiss() {
+ return mAutoDismiss;
+ }
+
+ /**
+ * Returns the data for the Intent that will be issued when the user clicks on the
+ * recommendation.
+ *
+ * @return An IntentData object, containing the data for the Intent that gets issued when the
+ * recommendation is clicked on.
+ */
+ public IntentData getContentIntent() {
+ return mContentIntentData;
+ }
+
+ /**
+ * Returns the data for the Intent that will be issued when the recommendation gets dismissed
+ * from the Home Screen, due to an user action.
+ *
+ * @return An IntentData object, containing the data for the Intent that gets issued when the
+ * recommendation is dismissed from the Home Screen.
+ */
+ public IntentData getDismissIntent() {
+ return mDismissIntentData;
+ }
+
+ /**
+ * Returns an array containing the content types tags that describe the content. The first tag
+ * entry is considered the primary type for the content, and is used for content ranking
+ * purposes.
+ *
+ * @return An array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants) that
+ * describe the recommended content.
+ */
+ public String[] getContentTypes() {
+ if (mContentTypes != null) {
+ return Arrays.copyOf(mContentTypes, mContentTypes.length);
+ }
+ return mContentTypes;
+ }
+
+ /**
+ * Returns the primary content type tag for the recommendation, or null if no content types have
+ * been specified.
+ *
+ * @return A predefined type tag (see the <code>CONTENT_TYPE_*</code> constants) indicating the
+ * primary content type for the recommendation.
+ */
+ public String getPrimaryContentType() {
+ if (mContentTypes != null && mContentTypes.length > 0) {
+ return mContentTypes[0];
+ }
+ return null;
+ }
+
+ /**
+ * Returns an array containing the genres that describe the content. Genres are open ended
+ * String tags.
+ *
+ * @return An array of genre tags that describe the recommended content.
+ */
+ public String[] getGenres() {
+ if (mContentGenres != null) {
+ return Arrays.copyOf(mContentGenres, mContentGenres.length);
+ }
+ return mContentGenres;
+ }
+
+ /**
+ * Gets the pricing type for the content.
+ *
+ * @return A predefined tag indicating the pricing type for the content (see the <code>
+ * CONTENT_PRICING_*</code> constants).
+ */
+ public String getPricingType() {
+ return mPriceType;
+ }
+
+ /**
+ * Gets the price value (when applicable) for the content. The value will be provided as a
+ * String containing the price in the appropriate currency for the current locale.
+ *
+ * @return A string containing a representation of the content price in the current locale and
+ * currency.
+ */
+ public String getPricingValue() {
+ return mPriceValue;
+ }
+
+ /**
+ * Sets the availability status value for the content. This status indicates whether the content
+ * is ready to be consumed on the device, or if the user must first purchase, rent, subscribe
+ * to, or download the content.
+ *
+ * @param status The status value for the content. (see the <code>CONTENT_STATUS_*</code> for
+ * the valid status values).
+ */
+ public void setStatus(@ContentStatus int status) {
+ mStatus = status;
+ }
+
+ /**
+ * Returns availability status value for the content. This status indicates whether the content
+ * is ready to be consumed on the device, or if the user must first purchase, rent, subscribe
+ * to, or download the content.
+ *
+ * @return The status value for the content, or -1 is a valid status has not been specified (see
+ * the <code>CONTENT_STATUS_*</code> constants for the valid status values).
+ */
+ public int getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * Returns the maturity level rating for the content.
+ *
+ * @return returns a predefined tag indicating the maturity level rating for the content (see
+ * the <code>CONTENT_MATURITY_*</code> constants).
+ */
+ public String getMaturityRating() {
+ return mMaturityRating;
+ }
+
+ /**
+ * Returns the running time for the content.
+ *
+ * @return The run length, in seconds, of the content associated with the notification.
+ */
+ public long getRunningTime() {
+ return mRunningTime;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ContentRecommendation) {
+ return TextUtils.equals(mIdTag, ((ContentRecommendation) other).getIdTag());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (mIdTag != null) {
+ return mIdTag.hashCode();
+ }
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Builder class for {@link ContentRecommendation} objects. Provides a convenient way to set the
+ * various fields of a {@link ContentRecommendation}.
+ * <p>
+ * Example:
+ *
+ * <pre class="prettyprint">
+ * ContentRecommendation rec = new ContentRecommendation.Builder()
+ * .setIdInfo(id, "MyTagId")
+ * .setTitle("My Content Recommendation")
+ * .setText("An example of content recommendation")
+ * .setContentImage(myBitmap)
+ * .setBadgeIcon(R.drawable.app_icon)
+ * .setGroup("Trending")
+ * .build();
+ * </pre>
+ */
+ public static final class Builder {
+ private String mBuilderIdTag;
+ private String mBuilderTitle;
+ private String mBuilderText;
+ private String mBuilderSourceName;
+ private Bitmap mBuilderContentImage;
+ private int mBuilderBadgeIconId;
+ private String mBuilderBackgroundImageUri;
+ private int mBuilderColor;
+ private String mBuilderGroup;
+ private String mBuilderSortKey;
+ private int mBuilderProgressAmount;
+ private int mBuilderProgressMax;
+ private boolean mBuilderAutoDismiss;
+ private IntentData mBuilderContentIntentData;
+ private IntentData mBuilderDismissIntentData;
+ private String[] mBuilderContentTypes;
+ private String[] mBuilderContentGenres;
+ private String mBuilderPriceType;
+ private String mBuilderPriceValue;
+ private int mBuilderStatus;
+ private String mBuilderMaturityRating;
+ private long mBuilderRunningTime;
+
+ /**
+ * Constructs a new Builder.
+ *
+ */
+ public Builder() {
+ }
+
+ /**
+ * Sets the Id tag that uniquely identifies this recommendation object.
+ *
+ * @param idTag A String tag identifier for this recommendation.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setIdTag(String idTag) {
+ mBuilderIdTag = checkNotNull(idTag);
+ return this;
+ }
+
+ /**
+ * Sets the content title for the recommendation.
+ *
+ * @param title A String containing the recommendation content title.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setTitle(String title) {
+ mBuilderTitle = checkNotNull(title);
+ return this;
+ }
+
+ /**
+ * Sets the description text for the recommendation.
+ *
+ * @param description A String containing the recommendation description text.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setText(@Nullable String description) {
+ mBuilderText = description;
+ return this;
+ }
+
+ /**
+ * Sets the source application name for the recommendation.
+ * <P>
+ * If the source name is never set, or set to null, the application name retrieved from its
+ * package will be used by default.
+ *
+ * @param source A String containing the recommendation source name.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setSourceName(@Nullable String source) {
+ mBuilderSourceName = source;
+ return this;
+ }
+
+ /**
+ * Sets the recommendation image.
+ *
+ * @param image A Bitmap containing the recommendation image.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setContentImage(Bitmap image) {
+ mBuilderContentImage = checkNotNull(image);
+ return this;
+ }
+
+ /**
+ * Sets the resource ID for the recommendation badging icon.
+ * <p>
+ * The resource id represents the icon resource in the source application package. If not
+ * set, or an invalid resource ID is specified, the application icon retrieved from its
+ * package will be used by default.
+ *
+ * @param iconResourceId An integer id for the badge icon resource.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setBadgeIcon(int iconResourceId) {
+ mBuilderBadgeIconId = iconResourceId;
+ return this;
+ }
+
+ /**
+ * Sets the Content URI that will be used to retrieve the background image for the
+ * recommendation.
+ *
+ * @param imageUri A Content URI pointing to the recommendation background image.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setBackgroundImageUri(@Nullable String imageUri) {
+ mBuilderBackgroundImageUri = imageUri;
+ return this;
+ }
+
+ /**
+ * Sets the accent color value to be used in the UI when displaying this content
+ * recommendation to the user.
+ *
+ * @param color An integer value representing the accent color for this recommendation.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setColor(int color) {
+ mBuilderColor = color;
+ return this;
+ }
+
+ /**
+ * Sets the String group ID tag for the recommendation.
+ * <p>
+ * Recommendations in the same group are ranked by the Home Screen together, and the sort
+ * order within a group is respected. This can be useful if the application has different
+ * sources for recommendations, like "trending", "subscriptions", and "new music" categories
+ * for YouTube, where the user can be more interested in recommendations from one group than
+ * another.
+ *
+ * @param groupTag A String containing the group ID tag for this recommendation.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setGroup(@Nullable String groupTag) {
+ mBuilderGroup = groupTag;
+ return this;
+ }
+
+ /**
+ * Sets the String sort key for the recommendation.
+ * <p>
+ * The sort key must be a String representation of a float number between 0.0 and 1.0, and
+ * is used to indicate the relative importance (and sort order) of a single recommendation
+ * within its specified group. The recommendations will be ordered in decreasing order of
+ * importance within a given group.
+ *
+ * @param sortKey A String containing the sort key for this recommendation.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setSortKey(@Nullable String sortKey) {
+ mBuilderSortKey = sortKey;
+ return this;
+ }
+
+ /**
+ * Sets the progress information for the content pointed to by the recommendation.
+ *
+ * @param max The maximum value for the progress of this content.
+ * @param progress The progress amount for this content. Must be in the range (0 - max).
+ * @return The Builder object, for chaining.
+ */
+ public Builder setProgress(int max, int progress) {
+ if (max < 0 || progress < 0) {
+ throw new IllegalArgumentException();
+ }
+ mBuilderProgressMax = max;
+ mBuilderProgressAmount = progress;
+ return this;
+ }
+
+ /**
+ * Sets the flag indicating if the recommendation should be dismissed automatically.
+ * <p>
+ * Auto-dismiss notifications are automatically removed from the Home Screen when the user
+ * clicks on them.
+ *
+ * @param autoDismiss A boolean indicating if the recommendation should be auto dismissed or
+ * not.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setAutoDismiss(boolean autoDismiss) {
+ mBuilderAutoDismiss = autoDismiss;
+ return this;
+ }
+
+ /**
+ * Sets the data for the Intent that will be issued when the user clicks on the
+ * recommendation.
+ * <p>
+ * The Intent data fields provided correspond to the fields passed into the
+ * {@link PendingIntent} factory methods, when creating a new PendingIntent. The actual
+ * PengindIntent object will only be created at the time a recommendation is posted to the
+ * Home Screen.
+ *
+ * @param intentType The type of {@link PendingIntent} to be created when posting this
+ * recommendation.
+ * @param intent The Intent which to be issued when the recommendation is clicked on.
+ * @param requestCode The private request code to be used when creating the
+ * {@link PendingIntent}
+ * @param options Only used for the Activity Intent type. Additional options for how the
+ * Activity should be started. May be null if there are no options.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setContentIntentData(@IntentType int intentType, Intent intent,
+ int requestCode, @Nullable Bundle options) {
+ if (intentType != INTENT_TYPE_ACTIVITY &&
+ intentType != INTENT_TYPE_BROADCAST &&
+ intentType != INTENT_TYPE_SERVICE) {
+ throw new IllegalArgumentException("Invalid Intent type specified.");
+ }
+
+ mBuilderContentIntentData = new IntentData();
+ mBuilderContentIntentData.mType = intentType;
+ mBuilderContentIntentData.mIntent = checkNotNull(intent);
+ mBuilderContentIntentData.mRequestCode = requestCode;
+ mBuilderContentIntentData.mOptions = options;
+
+ return this;
+ }
+
+ /**
+ * Sets the data for the Intent that will be issued when the recommendation gets dismissed
+ * from the Home Screen, due to an user action.
+ * <p>
+ * The Intent data fields provided correspond to the fields passed into the
+ * {@link PendingIntent} factory methods, when creating a new PendingIntent. The actual
+ * PengindIntent object will only be created at the time a recommendation is posted to the
+ * Home Screen.
+ *
+ * @param intentType The type of {@link PendingIntent} to be created when posting this
+ * recommendation.
+ * @param intent The Intent which gets issued when the recommendation is dismissed from the
+ * Home Screen.
+ * @param requestCode The private request code to be used when creating the
+ * {@link PendingIntent}
+ * @param options Only used for the Activity Intent type. Additional options for how the
+ * Activity should be started. May be null if there are no options.
+ * @return The Builder object, for chaining.
+ */
+ public Builder setDismissIntentData(@IntentType int intentType, @Nullable Intent intent,
+ int requestCode, @Nullable Bundle options) {
+ if (intent != null) {
+ if (intentType != INTENT_TYPE_ACTIVITY &&
+ intentType != INTENT_TYPE_BROADCAST &&
+ intentType != INTENT_TYPE_SERVICE) {
+ throw new IllegalArgumentException("Invalid Intent type specified.");
+ }
+
+ mBuilderDismissIntentData = new IntentData();
+ mBuilderDismissIntentData.mType = intentType;
+ mBuilderDismissIntentData.mIntent = intent;
+ mBuilderDismissIntentData.mRequestCode = requestCode;
+ mBuilderDismissIntentData.mOptions = options;
+ } else {
+ mBuilderDismissIntentData = null;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the content types associated with the content recommendation. The first tag entry
+ * will be considered the primary type for the content and will be used for ranking
+ * purposes. Other secondary type tags may be provided, if applicable, and may be used for
+ * filtering purposes.
+ *
+ * @param types Array of predefined type tags (see the <code>CONTENT_TYPE_*</code>
+ * constants) that describe the recommended content.
+ */
+ public Builder setContentTypes(String[] types) {
+ mBuilderContentTypes = checkNotNull(types);
+ return this;
+ }
+
+ /**
+ * Sets the content genres for the recommendation. These genres may be used for content
+ * ranking. Genres are open ended String tags.
+ * <p>
+ * Some examples: "comedy", "action", "dance", "electronica", "racing", etc.
+ *
+ * @param genres Array of genre string tags that describe the recommended content.
+ */
+ public Builder setGenres(String[] genres) {
+ mBuilderContentGenres = genres;
+ return this;
+ }
+
+ /**
+ * Sets the pricing and availability information for the recommendation. The provided
+ * information will indicate the access model for the content (free, rental, purchase or
+ * subscription) and the price value (if not free).
+ *
+ * @param priceType Pricing type for this content. Must be one of the predefined pricing
+ * type tags (see the <code>CONTENT_PRICING_*</code> constants).
+ * @param priceValue A string containing a representation of the content price in the
+ * current locale and currency.
+ */
+ public Builder setPricingInformation(@ContentPricing String priceType,
+ @Nullable String priceValue) {
+ mBuilderPriceType = checkNotNull(priceType);
+ mBuilderPriceValue = priceValue;
+ return this;
+ }
+
+ /**
+ * Sets the availability status for the content. This status indicates whether the referred
+ * content is ready to be consumed on the device, or if the user must first purchase, rent,
+ * subscribe to, or download the content.
+ *
+ * @param contentStatus The status value for this content. Must be one of the predefined
+ * content status values (see the <code>CONTENT_STATUS_*</code> constants).
+ */
+ public Builder setStatus(@ContentStatus int contentStatus) {
+ mBuilderStatus = contentStatus;
+ return this;
+ }
+
+ /**
+ * Sets the maturity level rating for the content.
+ *
+ * @param maturityRating A tag indicating the maturity level rating for the content. This
+ * tag must be one of the predefined maturity rating tags (see the <code>
+ * CONTENT_MATURITY_*</code> constants).
+ */
+ public Builder setMaturityRating(@ContentMaturity String maturityRating) {
+ mBuilderMaturityRating = checkNotNull(maturityRating);
+ return this;
+ }
+
+ /**
+ * Sets the running time (when applicable) for the content.
+ *
+ * @param length The running time, in seconds, of the content.
+ */
+ public Builder setRunningTime(long length) {
+ if (length < 0) {
+ throw new IllegalArgumentException();
+ }
+ mBuilderRunningTime = length;
+ return this;
+ }
+
+ /**
+ * Combine all of the options that have been set and return a new
+ * {@link ContentRecommendation} object.
+ */
+ public ContentRecommendation build() {
+ return new ContentRecommendation(this);
+ }
+ }
+
+ /**
+ * Returns a {@link android.app.Notification Notification} object which contains the content
+ * recommendation data encapsulated by this object, which can be used for posting the
+ * recommendation via the {@link android.app.NotificationManager NotificationManager}.
+ *
+ * @param context A {@link Context} that will be used to construct the
+ * {@link android.app.Notification Notification} object which will carry the
+ * recommendation data.
+ * @return A {@link android.app.Notification Notification} containing the stored recommendation
+ * data.
+ */
+ public Notification getNotificationObject(Context context) {
+ Notification.Builder builder = new Notification.Builder(context);
+ RecommendationExtender recExtender = new RecommendationExtender();
+
+ // Encode all the content recommendation data in a Notification object
+
+ builder.setCategory(Notification.CATEGORY_RECOMMENDATION);
+ builder.setContentTitle(mTitle);
+ builder.setContentText(mText);
+ builder.setContentInfo(mSourceName);
+ builder.setLargeIcon(mContentImage);
+ builder.setSmallIcon(mBadgeIconId);
+ if (mBackgroundImageUri != null) {
+ builder.getExtras().putString(Notification.EXTRA_BACKGROUND_IMAGE_URI,
+ mBackgroundImageUri);
+ }
+ builder.setColor(mColor);
+ builder.setGroup(mGroup);
+ builder.setSortKey(mSortKey);
+ builder.setProgress(mProgressMax, mProgressAmount, false);
+ builder.setAutoCancel(mAutoDismiss);
+
+ if (mContentIntentData != null) {
+ PendingIntent contentPending;
+ if (mContentIntentData.mType == INTENT_TYPE_ACTIVITY) {
+ contentPending = PendingIntent.getActivity(context, mContentIntentData.mRequestCode,
+ mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT,
+ mContentIntentData.mOptions);
+ } else if (mContentIntentData.mType == INTENT_TYPE_SERVICE) {
+ contentPending = PendingIntent.getService(context, mContentIntentData.mRequestCode,
+ mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ } else { // Default:INTENT_TYPE_BROADCAST{
+ contentPending = PendingIntent.getBroadcast(context,
+ mContentIntentData.mRequestCode,
+ mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+ builder.setContentIntent(contentPending);
+ }
+
+ if (mDismissIntentData != null) {
+ PendingIntent dismissPending;
+ if (mDismissIntentData.mType == INTENT_TYPE_ACTIVITY) {
+ dismissPending = PendingIntent.getActivity(context, mDismissIntentData.mRequestCode,
+ mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT,
+ mDismissIntentData.mOptions);
+ } else if (mDismissIntentData.mType == INTENT_TYPE_SERVICE) {
+ dismissPending = PendingIntent.getService(context, mDismissIntentData.mRequestCode,
+ mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ } else { // Default:INTENT_TYPE_BROADCAST{
+ dismissPending = PendingIntent.getBroadcast(context,
+ mDismissIntentData.mRequestCode,
+ mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+ builder.setDeleteIntent(dismissPending);
+ }
+
+ recExtender.setContentTypes(mContentTypes);
+ recExtender.setGenres(mContentGenres);
+ recExtender.setPricingInformation(mPriceType, mPriceValue);
+ recExtender.setStatus(mStatus);
+ recExtender.setMaturityRating(mMaturityRating);
+ recExtender.setRunningTime(mRunningTime);
+
+ builder.extend(recExtender);
+ Notification notif = builder.build();
+ return notif;
+ }
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling method is not null.
+ *
+ * @param reference an object reference
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ private static <T> T checkNotNull(final T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ }
+ return reference;
+ }
+
+}
\ No newline at end of file
diff --git a/recommendation/src/android/support/app/recommendation/RecommendationExtender.java b/recommendation/src/android/support/app/recommendation/RecommendationExtender.java
new file mode 100644
index 0000000..5762a28
--- /dev/null
+++ b/recommendation/src/android/support/app/recommendation/RecommendationExtender.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.app.recommendation;
+
+import android.app.Notification;
+import android.os.Bundle;
+
+/**
+ * <p>
+ * Helper class to add content info extensions to notifications. To create a notification with
+ * content info extensions:
+ * <ol>
+ * <li>Create an {@link Notification.Builder}, setting any desired properties.
+ * <li>Create a {@link RecommendationExtender}.
+ * <li>Set content info specific properties using the {@code add} and {@code set} methods of
+ * {@link RecommendationExtender}.
+ * <li>Call {@link android.app.Notification.Builder#extend(Notification.Extender)
+ * Notification.Builder.extend(Notification.Extender)} to apply the extensions to a notification.
+ * </ol>
+ *
+ * <pre class="prettyprint">Notification notification = new Notification.Builder(context) * ... * .extend(new RecommendationExtender() * .set*(...)) * .build(); * </pre>
+ * <p>
+ * Content info extensions can be accessed on an existing notification by using the
+ * {@code RecommendationExtender(Notification)} constructor, and then using the {@code get} methods
+ * to access values.
+ */
+public final class RecommendationExtender implements Notification.Extender {
+ private static final String TAG = "RecommendationExtender";
+
+ // Key for the Content info extensions bundle in the main Notification extras bundle
+ private static final String EXTRA_CONTENT_INFO_EXTENDER = "android.CONTENT_INFO_EXTENSIONS";
+
+ // Keys within EXTRA_CONTENT_INFO_EXTENDER for individual content info options.
+
+ private static final String KEY_CONTENT_TYPE = "android.contentType";
+
+ private static final String KEY_CONTENT_GENRES = "android.contentGenre";
+
+ private static final String KEY_CONTENT_PRICING_TYPE = "android.contentPricing.type";
+
+ private static final String KEY_CONTENT_PRICING_VALUE = "android.contentPricing.value";
+
+ private static final String KEY_CONTENT_STATUS = "android.contentStatus";
+
+ private static final String KEY_CONTENT_MATURITY_RATING = "android.contentMaturity";
+
+ private static final String KEY_CONTENT_RUN_LENGTH = "android.contentLength";
+
+ private String[] mTypes;
+ private String[] mGenres;
+ private String mPricingType;
+ private String mPricingValue;
+ private int mContentStatus = -1;
+ private String mMaturityRating;
+ private long mRunLength = -1;
+
+ /**
+ * Create a {@link RecommendationExtender} with default options.
+ */
+ public RecommendationExtender() {
+ }
+
+ /**
+ * Create a {@link RecommendationExtender} from the RecommendationExtender options of an
+ * existing Notification.
+ *
+ * @param notif The notification from which to copy options.
+ */
+ public RecommendationExtender(Notification notif) {
+ Bundle contentBundle = notif.extras == null ?
+ null : notif.extras.getBundle(EXTRA_CONTENT_INFO_EXTENDER);
+ if (contentBundle != null) {
+ mTypes = contentBundle.getStringArray(KEY_CONTENT_TYPE);
+ mGenres = contentBundle.getStringArray(KEY_CONTENT_GENRES);
+ mPricingType = contentBundle.getString(KEY_CONTENT_PRICING_TYPE);
+ mPricingValue = contentBundle.getString(KEY_CONTENT_PRICING_VALUE);
+ mContentStatus = contentBundle.getInt(KEY_CONTENT_STATUS, -1);
+ mMaturityRating = contentBundle.getString(KEY_CONTENT_MATURITY_RATING);
+ mRunLength = contentBundle.getLong(KEY_CONTENT_RUN_LENGTH, -1);
+ }
+ }
+
+ /**
+ * Apply content extensions to a notification that is being built. This is typically called by
+ * the {@link android.app.Notification.Builder#extend(Notification.Extender)
+ * Notification.Builder.extend(Notification.Extender)} method of {@link Notification.Builder}.
+ */
+ @Override
+ public Notification.Builder extend(Notification.Builder builder) {
+ Bundle contentBundle = new Bundle();
+
+ if (mTypes != null) {
+ contentBundle.putStringArray(KEY_CONTENT_TYPE, mTypes);
+ }
+ if (mGenres != null) {
+ contentBundle.putStringArray(KEY_CONTENT_GENRES, mGenres);
+ }
+ if (mPricingType != null) {
+ contentBundle.putString(KEY_CONTENT_PRICING_TYPE, mPricingType);
+ }
+ if (mPricingValue != null) {
+ contentBundle.putString(KEY_CONTENT_PRICING_VALUE, mPricingValue);
+ }
+ if (mContentStatus != -1) {
+ contentBundle.putInt(KEY_CONTENT_STATUS, mContentStatus);
+ }
+ if (mMaturityRating != null) {
+ contentBundle.putString(KEY_CONTENT_MATURITY_RATING, mMaturityRating);
+ }
+ if (mRunLength > 0) {
+ contentBundle.putLong(KEY_CONTENT_RUN_LENGTH, mRunLength);
+ }
+
+ builder.getExtras().putBundle(EXTRA_CONTENT_INFO_EXTENDER, contentBundle);
+ return builder;
+ }
+
+ /**
+ * Sets the content types associated with the notification content. The first tag entry will be
+ * considered the primary type for the content and will be used for ranking purposes. Other
+ * secondary type tags may be provided, if applicable, and may be used for filtering purposes.
+ *
+ * @param types Array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants)
+ * that describe the content referred to by a notification.
+ */
+ public RecommendationExtender setContentTypes(String[] types) {
+ mTypes = types;
+ return this;
+ }
+
+ /**
+ * Returns an array containing the content types that describe the content associated with the
+ * notification. The first tag entry is considered the primary type for the content, and is used
+ * for content ranking purposes.
+ *
+ * @return An array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants) that
+ * describe the content associated with the notification.
+ * @see RecommendationExtender#setContentTypes
+ */
+ public String[] getContentTypes() {
+ return mTypes;
+ }
+
+ /**
+ * Returns the primary content type tag for the content associated with the notification.
+ *
+ * @return A predefined type tag (see the <code>CONTENT_TYPE_*</code> constants) indicating the
+ * primary type for the content associated with the notification.
+ * @see RecommendationExtender#setContentTypes
+ */
+ public String getPrimaryContentType() {
+ if (mTypes == null || mTypes.length == 0) {
+ return null;
+ }
+ return mTypes[0];
+ }
+
+ /**
+ * Sets the content genres associated with the notification content. These genres may be used
+ * for content ranking. Genres are open ended String tags.
+ * <p>
+ * Some examples: "comedy", "action", "dance", "electronica", "racing", etc.
+ *
+ * @param genres Array of genre string tags that describe the content referred to by a
+ * notification.
+ */
+ public RecommendationExtender setGenres(String[] genres) {
+ mGenres = genres;
+ return this;
+ }
+
+ /**
+ * Returns an array containing the content genres that describe the content associated with the
+ * notification.
+ *
+ * @return An array of genre tags that describe the content associated with the notification.
+ * @see RecommendationExtender#setGenres
+ */
+ public String[] getGenres() {
+ return mGenres;
+ }
+
+ /**
+ * Sets the pricing and availability information for the content associated with the
+ * notification. The provided information will indicate the access model for the content (free,
+ * rental, purchase or subscription) and the price value (if not free).
+ *
+ * @param priceType Pricing type for this content. Must be one of the predefined pricing type
+ * tags (see the <code>CONTENT_PRICING_*</code> constants).
+ * @param priceValue A string containing a representation of the content price in the current
+ * locale and currency.
+ * @return This object for method chaining.
+ */
+ public RecommendationExtender setPricingInformation(
+ @ContentRecommendation.ContentPricing String priceType, String priceValue) {
+ mPricingType = priceType;
+ mPricingValue = priceValue;
+ return this;
+ }
+
+ /**
+ * Gets the pricing type for the content associated with the notification.
+ *
+ * @return A predefined tag indicating the pricing type for the content (see the <code> CONTENT_PRICING_*</code>
+ * constants).
+ * @see RecommendationExtender#setPricingInformation
+ */
+ public String getPricingType() {
+ return mPricingType;
+ }
+
+ /**
+ * Gets the price value (when applicable) for the content associated with a notification. The
+ * value will be provided as a String containing the price in the appropriate currency for the
+ * current locale.
+ *
+ * @return A string containing a representation of the content price in the current locale and
+ * currency.
+ * @see RecommendationExtender#setPricingInformation
+ */
+ public String getPricingValue() {
+ if (mPricingType == null) {
+ return null;
+ }
+ return mPricingValue;
+ }
+
+ /**
+ * Sets the availability status for the content associated with the notification. This status
+ * indicates whether the referred content is ready to be consumed on the device, or if the user
+ * must first purchase, rent, subscribe to, or download the content.
+ *
+ * @param contentStatus The status value for this content. Must be one of the predefined content
+ * status values (see the <code>CONTENT_STATUS_*</code> constants).
+ */
+ public RecommendationExtender setStatus(
+ @ContentRecommendation.ContentStatus int contentStatus) {
+ mContentStatus = contentStatus;
+ return this;
+ }
+
+ /**
+ * Returns status value for the content associated with the notification. This status indicates
+ * whether the referred content is ready to be consumed on the device, or if the user must first
+ * purchase, rent, subscribe to, or download the content.
+ *
+ * @return The status value for this content, or -1 is a valid status has not been specified
+ * (see the <code>CONTENT_STATUS_*</code> for the defined valid status values).
+ * @see RecommendationExtender#setStatus
+ */
+ public int getStatus() {
+ return mContentStatus;
+ }
+
+ /**
+ * Sets the maturity level rating for the content associated with the notification.
+ *
+ * @param maturityRating A tag indicating the maturity level rating for the content. This tag
+ * must be one of the predefined maturity rating tags (see the <code> CONTENT_MATURITY_*</code>
+ * constants).
+ */
+ public RecommendationExtender setMaturityRating(
+ @ContentRecommendation.ContentMaturity String maturityRating) {
+ mMaturityRating = maturityRating;
+ return this;
+ }
+
+ /**
+ * Returns the maturity level rating for the content associated with the notification.
+ *
+ * @return returns a predefined tag indicating the maturity level rating for the content (see
+ * the <code>CONTENT_MATURITY_*</code> constants).
+ * @see RecommendationExtender#setMaturityRating
+ */
+ public String getMaturityRating() {
+ return mMaturityRating;
+ }
+
+ /**
+ * Sets the running time (when applicable) for the content associated with the notification.
+ *
+ * @param length The runing time, in seconds, of the content associated with the notification.
+ */
+ public RecommendationExtender setRunningTime(long length) {
+ if (length < 0) {
+ throw new IllegalArgumentException("Invalid value for Running Time");
+ }
+ mRunLength = length;
+ return this;
+ }
+
+ /**
+ * Returns the running time for the content associated with the notification.
+ *
+ * @return The running time, in seconds, of the content associated with the notification.
+ * @see RecommendationExtender#setRunningTime
+ */
+ public long getRunningTime() {
+ return mRunLength;
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index ce5bf86..85c9ae1 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -22,6 +22,15 @@
include ':support-cardview-v7'
project(':support-cardview-v7').projectDir = new File(rootDir, 'v7/cardview')
+include ':support-preference-v7'
+project(':support-preference-v7').projectDir = new File(rootDir, 'v7/preference')
+
+include ':support-preference-v14'
+project(':support-preference-v14').projectDir = new File(rootDir, 'v14/preference')
+
+include ':support-preference-leanback-v17'
+project(':support-preference-leanback-v17').projectDir = new File(rootDir, 'v17/preference-leanback')
+
include ':support-v13'
project(':support-v13').projectDir = new File(rootDir, 'v13')
diff --git a/tests/java/android/support/v4/text/IcuCompatTest.java b/tests/java/android/support/v4/text/IcuCompatTest.java
new file mode 100644
index 0000000..6f7f459
--- /dev/null
+++ b/tests/java/android/support/v4/text/IcuCompatTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.text;
+
+import junit.framework.TestCase;
+
+import java.util.Locale;
+
+public class IcuCompatTest extends TestCase {
+ public void testMaximizeAndGetScript() {
+ assertEquals("Latn", ICUCompat.maximizeAndGetScript(new Locale("en", "US")));
+ assertEquals("Visp", ICUCompat.maximizeAndGetScript(Locale.forLanguageTag("en-Visp-US")));
+ }
+}
diff --git a/v13/Android.mk b/v13/Android.mk
index e5a137b..c61b112 100644
--- a/v13/Android.mk
+++ b/v13/Android.mk
@@ -32,6 +32,14 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13-ics
include $(BUILD_STATIC_JAVA_LIBRARY)
+# A helper sub-library that makes direct use of MNC APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v13-mnc
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13-ics-mr1
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
# -----------------------------------------------------------------------
include $(CLEAR_VARS)
@@ -39,7 +47,8 @@
LOCAL_SDK_VERSION := 13
LOCAL_SRC_FILES := $(call all-java-files-under, java)
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4 \
- android-support-v13-ics-mr1
+ android-support-v13-ics-mr1 \
+ android-support-v13-mnc
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v13/api/current.txt b/v13/api/current.txt
index 6b070c5..36ea6c0 100644
--- a/v13/api/current.txt
+++ b/v13/api/current.txt
@@ -2,8 +2,14 @@
public class FragmentCompat {
ctor public FragmentCompat();
+ method public static void requestPermissions(android.app.Fragment, java.lang.String[], int);
method public static void setMenuVisibility(android.app.Fragment, boolean);
method public static void setUserVisibleHint(android.app.Fragment, boolean);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Fragment, java.lang.String);
+ }
+
+ public static abstract interface FragmentCompat.OnRequestPermissionsResultCallback {
+ method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
}
public abstract class FragmentPagerAdapter extends android.support.v4.view.PagerAdapter {
diff --git a/v13/api23/android/support/v13/app/FragmentCompat23.java b/v13/api23/android/support/v13/app/FragmentCompat23.java
new file mode 100644
index 0000000..5027240
--- /dev/null
+++ b/v13/api23/android/support/v13/app/FragmentCompat23.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v13.app;
+
+import android.app.Fragment;
+
+class FragmentCompat23 {
+ public static void requestPermissions(Fragment fragment, String[] permissions,
+ int requestCode) {
+ fragment.requestPermissions(permissions, requestCode);
+ }
+
+ public static boolean shouldShowRequestPermissionRationale(Fragment fragment,
+ String permission) {
+ return fragment.shouldShowRequestPermissionRationale(permission);
+ }
+}
diff --git a/v13/build.gradle b/v13/build.gradle
index d0eb43e..c1e624b 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -9,8 +9,9 @@
ext.allSS = []
-def icsSS = createApiSourceset('ics', 'ics', '14', null)
-def icsMr1SS = createApiSourceset('icsmr1', 'ics-mr1', '15', icsSS)
+def icsSS = createApiSourceset('ics', 'ics', '14', null)
+def icsMr1SS = createApiSourceset('icsmr1', 'ics-mr1', '15', icsSS)
+def api23SS = createApiSourceset('api23', 'api23', 'current', icsMr1SS)
def createApiSourceset(String name, String folder, String apiLevel, SourceSet previousSource) {
def sourceSet = sourceSets.create(name)
diff --git a/v13/java/android/support/v13/app/FragmentCompat.java b/v13/java/android/support/v13/app/FragmentCompat.java
index eec3ea5..745bf91 100644
--- a/v13/java/android/support/v13/app/FragmentCompat.java
+++ b/v13/java/android/support/v13/app/FragmentCompat.java
@@ -17,6 +17,13 @@
package android.support.v13.app;
import android.app.Fragment;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+
+import java.util.Arrays;
/**
* Helper for accessing features in {@link Fragment} introduced after
@@ -26,6 +33,8 @@
interface FragmentCompatImpl {
void setMenuVisibility(Fragment f, boolean visible);
void setUserVisibleHint(Fragment f, boolean deferStart);
+ void requestPermissions(Fragment fragment, String[] permissions, int requestCode);
+ boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission);
}
static class BaseFragmentCompatImpl implements FragmentCompatImpl {
@@ -33,6 +42,22 @@
}
public void setUserVisibleHint(Fragment f, boolean deferStart) {
}
+ public void requestPermissions(final Fragment fragment, final String[] permissions,
+ final int requestCode) {
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ final int[] grantResults = new int[permissions.length];
+ Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
+ ((OnRequestPermissionsResultCallback) fragment).onRequestPermissionsResult(
+ requestCode, permissions, grantResults);
+ }
+ });
+ }
+ public boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission) {
+ return false;
+ }
}
static class ICSFragmentCompatImpl extends BaseFragmentCompatImpl {
@@ -49,9 +74,24 @@
}
}
+ static class MncFragmentCompatImpl extends ICSMR1FragmentCompatImpl {
+ @Override
+ public void requestPermissions(Fragment fragment, String[] permissions, int requestCode) {
+ FragmentCompat23.requestPermissions(fragment, permissions, requestCode);
+ }
+
+ @Override
+ public boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission) {
+ return FragmentCompat23.shouldShowRequestPermissionRationale(fragment, permission);
+ }
+ }
+
static final FragmentCompatImpl IMPL;
static {
- if (android.os.Build.VERSION.SDK_INT >= 15) {
+ // TODO: Change to comparison against API 23 once we have it defined.
+ if (Build.VERSION.CODENAME.equals("MNC") || Build.VERSION.SDK_INT > 22) {
+ IMPL = new MncFragmentCompatImpl();
+ } else if (android.os.Build.VERSION.SDK_INT >= 15) {
IMPL = new ICSMR1FragmentCompatImpl();
} else if (android.os.Build.VERSION.SDK_INT >= 14) {
IMPL = new ICSFragmentCompatImpl();
@@ -59,7 +99,30 @@
IMPL = new BaseFragmentCompatImpl();
}
}
-
+
+ /**
+ * This interface is the contract for receiving the results for permission requests.
+ */
+ public interface OnRequestPermissionsResultCallback {
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(android.app.Fragment,
+ * String[], int)}
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(
+ * android.app.Fragment, String[], int)}
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(android.app.Fragment, String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults);
+ }
+
/**
* Call {@link Fragment#setMenuVisibility(boolean) Fragment.setMenuVisibility(boolean)}
* if running on an appropriate version of the platform.
@@ -75,4 +138,86 @@
public static void setUserVisibleHint(Fragment f, boolean deferStart) {
IMPL.setUserVisibleHint(f, deferStart);
}
+
+ /**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback reporting whether the
+ * permissions were granted or not. Your fragment has to implement {@link
+ * OnRequestPermissionsResultCallback}
+ * and the results of permission requests will be delivered to its
+ * {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
+ * int, String[], int[])}.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to your onRequestPermissionsResult(
+ * int, String[], int[]).
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * android.support.v4.content.ContextCompat#checkSelfPermission(
+ * android.content.Context, String)}.
+ * </p>
+ *
+ * @param fragment The target fragment.
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
+ * int, String[], int[])}.
+ *
+ * @see android.support.v4.content.ContextCompat#checkSelfPermission(
+ * android.content.Context, String)
+ * @see #shouldShowRequestPermissionRationale(android.app.Fragment, String)
+ */
+ public static void requestPermissions(@NonNull Fragment fragment,
+ @NonNull String[] permissions, int requestCode) {
+ IMPL.requestPermissions(fragment, permissions, requestCode);
+ }
+
+ /**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from granting this permission.
+ * <p>
+ * For example, if you write a camera app, requesting the camera permission
+ * would be expected by the user and no rationale for why it is requested is
+ * needed. If however, the app needs location for tagging photos then a non-tech
+ * savvy user may wonder how location is related to taking photos. In this case
+ * you may choose to show UI with rationale of requesting this permission.
+ * </p>
+ *
+ * @param fragment The target fragment.
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @see android.support.v4.content.ContextCompat#checkSelfPermission(
+ * android.content.Context, String)
+ * @see #requestPermissions(android.app.Fragment, String[], int)
+ */
+ public static boolean shouldShowRequestPermissionRationale(@NonNull Fragment fragment,
+ @NonNull String permission) {
+ return IMPL.shouldShowRequestPermissionRationale(fragment, permission);
+ }
}
diff --git a/v14/Android.mk b/v14/Android.mk
new file mode 100644
index 0000000..365b3b1
--- /dev/null
+++ b/v14/Android.mk
@@ -0,0 +1,16 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/v14/preference/Android.mk b/v14/preference/Android.mk
new file mode 100644
index 0000000..fc7a9aa
--- /dev/null
+++ b/v14/preference/Android.mk
@@ -0,0 +1,59 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the resources using the current SDK version.
+# We do this here because the final static library must be compiled with an older
+# SDK version than the resources. The resources library and the R class that it
+# contains will not be linked into the final static library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v14-preference-res
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, dummy)
+LOCAL_RESOURCE_DIR := \
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/preference/res \
+ $(LOCAL_PATH)/res
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay
+LOCAL_JAR_EXCLUDE_FILES := none
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Here is the final static library that apps can link against.
+# The R class is automatically excluded from the generated library.
+# Applications that use this library must specify LOCAL_RESOURCE_DIR
+# in their makefiles to include the resources in their package.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v14-preference
+LOCAL_SDK_VERSION := 14
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+# LOCAL_STATIC_JAVA_LIBRARIES :=
+LOCAL_JAVA_LIBRARIES := \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview \
+ android-support-v7-preference \
+ android-support-annotations \
+ android-support-v14-preference-res
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# API Check
+# ---------------------------------------------
+support_module := $(LOCAL_MODULE)
+support_module_api_dir := $(LOCAL_PATH)/api
+support_module_src_files := $(LOCAL_SRC_FILES)
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
+support_module_java_packages := android.support.v14.preference
+include $(SUPPORT_API_CHECK)
\ No newline at end of file
diff --git a/v14/preference/AndroidManifest.xml b/v14/preference/AndroidManifest.xml
new file mode 100644
index 0000000..8b502c9
--- /dev/null
+++ b/v14/preference/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.v14.preference"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="14" />
+ <application />
+</manifest>
diff --git a/v14/preference/api/current.txt b/v14/preference/api/current.txt
new file mode 100644
index 0000000..cbf8fe5
--- /dev/null
+++ b/v14/preference/api/current.txt
@@ -0,0 +1,95 @@
+package android.support.v14.preference {
+
+ public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+ ctor public EditTextPreferenceDialogFragment();
+ method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
+ method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+ ctor public ListPreferenceDialogFragment();
+ method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class MultiSelectListPreference extends android.support.v7.preference.DialogPreference {
+ ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
+ ctor public MultiSelectListPreference(android.content.Context);
+ method public int findIndexOfValue(java.lang.String);
+ method public java.lang.CharSequence[] getEntries();
+ method public java.lang.CharSequence[] getEntryValues();
+ method protected boolean[] getSelectedItems();
+ method public java.util.Set<java.lang.String> getValues();
+ method public void setEntries(java.lang.CharSequence[]);
+ method public void setEntries(int);
+ method public void setEntryValues(java.lang.CharSequence[]);
+ method public void setEntryValues(int);
+ method public void setValues(java.util.Set<java.lang.String>);
+ }
+
+ public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
+ ctor public MultiSelectListPreferenceDialogFragment();
+ method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+ ctor public PreferenceDialogFragment();
+ method public android.support.v7.preference.DialogPreference getPreference();
+ method protected void onBindDialogView(android.view.View);
+ method public void onClick(android.content.DialogInterface, int);
+ method protected android.view.View onCreateDialogView(android.content.Context);
+ method public abstract void onDialogClosed(boolean);
+ method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
+ field protected static final java.lang.String ARG_KEY = "key";
+ }
+
+ public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+ ctor public PreferenceFragment();
+ method public void addPreferencesFromResource(int);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public final android.support.v7.widget.RecyclerView getListView();
+ method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+ method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+ method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+ method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+ method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+ method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+ method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+ method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+ method public void setPreferencesFromResource(int, java.lang.String);
+ field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+ }
+
+ public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
+ method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+ method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
+ method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
+ }
+
+ public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
+ ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
+ ctor public SwitchPreference(android.content.Context);
+ method public java.lang.CharSequence getSwitchTextOff();
+ method public java.lang.CharSequence getSwitchTextOn();
+ method public void setSwitchTextOff(java.lang.CharSequence);
+ method public void setSwitchTextOff(int);
+ method public void setSwitchTextOn(java.lang.CharSequence);
+ method public void setSwitchTextOn(int);
+ }
+
+}
+
diff --git a/v14/preference/api/removed.txt b/v14/preference/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v14/preference/api/removed.txt
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
new file mode 100644
index 0000000..772b353
--- /dev/null
+++ b/v14/preference/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+
+
+apply plugin: 'android-library'
+
+archivesBaseName = 'preference-v14'
+
+dependencies {
+ compile project(':support-v4')
+ compile project(':support-appcompat-v7')
+ compile project(':support-recyclerview-v7')
+ compile project(':support-preference-v7')
+}
+
+android {
+ compileSdkVersion 'current'
+
+ sourceSets {
+ main.manifest.srcFile 'AndroidManifest.xml'
+ main.java.srcDir 'src'
+ main.res.srcDir 'res'
+ main.assets.srcDir 'assets'
+ main.resources.srcDir 'src'
+
+ // this moves src/instrumentTest to tests so all folders follow:
+ // tests/java, tests/res, tests/assets, ...
+ // This is a *reset* so it replaces the default paths
+ androidTest.setRoot('tests')
+ androidTest.java.srcDir 'tests/src'
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ lintOptions {
+ // TODO: fix errors and reenable.
+ abortOnError false
+ }
+}
diff --git a/v14/preference/res/layout-v21/preference_material.xml b/v14/preference/res/layout-v21/preference_material.xml
new file mode 100644
index 0000000..8d62cc2
--- /dev/null
+++ b/v14/preference/res/layout-v21/preference_material.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-4dp"
+ android:minWidth="60dp"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal"
+ android:paddingEnd="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <android.support.v7.internal.widget.PreferenceImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:maxWidth="48dp"
+ app:maxHeight="48dp" />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+
+ <TextView android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:ellipsize="marquee" />
+
+ <TextView android:id="@+id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:layout_alignStart="@id/title"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingStart="16dp"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v14/preference/res/layout/preference_material.xml b/v14/preference/res/layout/preference_material.xml
new file mode 100644
index 0000000..b9d8f66
--- /dev/null
+++ b/v14/preference/res/layout/preference_material.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:clipToPadding="false">
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-4dp"
+ android:minWidth="60dp"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal"
+ android:paddingEnd="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <android.support.v7.internal.widget.PreferenceImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:maxWidth="48dp"
+ app:maxHeight="48dp" />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp">
+
+ <TextView android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:ellipsize="marquee" />
+
+ <TextView android:id="@+id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:layout_alignStart="@id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingStart="16dp"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v14/preference/res/layout/preference_widget_switch.xml b/v14/preference/res/layout/preference_widget_switch.xml
new file mode 100644
index 0000000..ae83afa
--- /dev/null
+++ b/v14/preference/res/layout/preference_widget_switch.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<!-- Layout used by SwitchPreference for the switch widget style. This is inflated
+ inside android.R.layout.preference. -->
+<Switch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/switchWidget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:background="@null" />
diff --git a/v14/preference/res/values/attrs.xml b/v14/preference/res/values/attrs.xml
new file mode 100644
index 0000000..62d9e47
--- /dev/null
+++ b/v14/preference/res/values/attrs.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <declare-styleable name="SwitchPreference">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" />
+ <attr name="android:summaryOff" />
+ <!-- The text used on the switch itself when in the "on" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOn"/>
+ <attr name="android:switchTextOn"/>
+ <!-- The text used on the switch itself when in the "off" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOff" />
+ <attr name="android:switchTextOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
+
+ <declare-styleable name="MultiSelectListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
+</resources>
diff --git a/v14/preference/res/values/styles.xml b/v14/preference/res/values/styles.xml
new file mode 100644
index 0000000..d7cc268
--- /dev/null
+++ b/v14/preference/res/values/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="Preference.SwitchPreference">
+ <item name="widgetLayout">@layout/preference_widget_switch</item>
+ <item name="switchTextOn">@string/v7_preference_on</item>
+ <item name="switchTextOff">@string/v7_preference_off</item>
+ </style>
+
+</resources>
diff --git a/v14/preference/res/values/themes.xml b/v14/preference/res/values/themes.xml
new file mode 100644
index 0000000..88d25d2
--- /dev/null
+++ b/v14/preference/res/values/themes.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="PreferenceThemeOverlay.v14">
+ <item name="switchPreferenceStyle">@style/Preference.SwitchPreference</item>
+ </style>
+</resources>
diff --git a/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
new file mode 100644
index 0000000..caf08a8
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/EditTextPreferenceDialogFragment.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v14.preference;
+
+import android.os.Bundle;
+import android.support.v7.preference.EditTextPreference;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.EditText;
+
+public class EditTextPreferenceDialogFragment extends PreferenceDialogFragment {
+
+ private EditText mEditText;
+
+ public static EditTextPreferenceDialogFragment newInstance(String key) {
+ final EditTextPreferenceDialogFragment
+ fragment = new EditTextPreferenceDialogFragment();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+ super.onBindDialogView(view);
+
+ mEditText = new EditText(view.getContext());
+ // Give it an ID so it can be saved/restored
+ mEditText.setId(android.R.id.edit);
+
+ mEditText.setText(getEditTextPreference().getText());
+
+ ViewParent oldParent = mEditText.getParent();
+ if (oldParent != view) {
+ if (oldParent != null) {
+ ((ViewGroup) oldParent).removeView(mEditText);
+ }
+ onAddEditTextToDialogView(view, mEditText);
+ }
+ }
+
+ private EditTextPreference getEditTextPreference() {
+ return (EditTextPreference) getPreference();
+ }
+
+ /** @hide */
+ @Override
+ protected boolean needInputMethod() {
+ // We want the input method to show, if possible, when dialog is displayed
+ return true;
+ }
+
+ /**
+ * Adds the EditText widget of this preference to the dialog's view.
+ *
+ * @param dialogView The dialog view.
+ */
+ protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
+ ViewGroup container = (ViewGroup) dialogView
+ .findViewById(R.id.edittext_container);
+ if (container != null) {
+ container.addView(editText, ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+
+ if (positiveResult) {
+ String value = mEditText.getText().toString();
+ if (getEditTextPreference().callChangeListener(value)) {
+ getEditTextPreference().setText(value);
+ }
+ }
+ }
+
+}
diff --git a/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
new file mode 100644
index 0000000..c4e922c
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/ListPreferenceDialogFragment.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v14.preference;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v7.preference.ListPreference;
+
+public class ListPreferenceDialogFragment extends PreferenceDialogFragment {
+
+ private int mClickedDialogEntryIndex;
+
+ public static ListPreferenceDialogFragment newInstance(String key) {
+ final ListPreferenceDialogFragment fragment = new ListPreferenceDialogFragment();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ private ListPreference getListPreference() {
+ return (ListPreference) getPreference();
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+
+ final ListPreference preference = getListPreference();
+
+ if (preference.getEntries() == null || preference.getEntryValues() == null) {
+ throw new IllegalStateException(
+ "ListPreference requires an entries array and an entryValues array.");
+ }
+
+ mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
+ builder.setSingleChoiceItems(preference.getEntries(), mClickedDialogEntryIndex,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mClickedDialogEntryIndex = which;
+
+ /*
+ * Clicking on an item simulates the positive button
+ * click, and dismisses the dialog.
+ */
+ ListPreferenceDialogFragment.this.onClick(dialog,
+ DialogInterface.BUTTON_POSITIVE);
+ dialog.dismiss();
+ }
+ });
+
+ /*
+ * The typical interaction for list-based dialogs is to have
+ * click-on-an-item dismiss the dialog instead of the user having to
+ * press 'Ok'.
+ */
+ builder.setPositiveButton(null, null);
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ final ListPreference preference = getListPreference();
+ if (positiveResult && mClickedDialogEntryIndex >= 0 &&
+ preference.getEntryValues() != null) {
+ String value = preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+ if (preference.callChangeListener(value)) {
+ preference.setValue(value);
+ }
+ }
+ }
+
+}
diff --git a/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java b/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
new file mode 100644
index 0000000..2a636fe
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/MultiSelectListPreference.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v14.preference;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.ArrayRes;
+import android.support.annotation.NonNull;
+import android.support.v4.content.SharedPreferencesCompat;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A {@link android.support.v7.preference.Preference} that displays a list of entries as
+ * a dialog.
+ * <p>
+ * This preference will store a set of strings into the SharedPreferences.
+ * This set will contain one or more values from the
+ * {@link #setEntryValues(CharSequence[])} array.
+ *
+ * @attr ref android.R.styleable#MultiSelectListPreference_entries
+ * @attr ref android.R.styleable#MultiSelectListPreference_entryValues
+ */
+public class MultiSelectListPreference extends DialogPreference {
+ private CharSequence[] mEntries;
+ private CharSequence[] mEntryValues;
+ private Set<String> mValues = new HashSet<>();
+
+ public MultiSelectListPreference(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.MultiSelectListPreference, defStyleAttr,
+ defStyleRes);
+
+ mEntries = TypedArrayUtils.getTextArray(a,
+ R.styleable.MultiSelectListPreference_entries,
+ R.styleable.MultiSelectListPreference_android_entries);
+
+ mEntryValues = TypedArrayUtils.getTextArray(a,
+ R.styleable.MultiSelectListPreference_entryValues,
+ R.styleable.MultiSelectListPreference_android_entryValues);
+
+ a.recycle();
+ }
+
+ public MultiSelectListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public MultiSelectListPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.dialogPreferenceStyle);
+ }
+
+ public MultiSelectListPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
+ * <p>
+ * This will check if this Preference is persistent, get an editor from
+ * the {@link android.preference.PreferenceManager}, put in the strings, and check if we should
+ * commit (and commit if so).
+ *
+ * @param values The values to persist.
+ * @return True if the Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #getPersistedString
+ *
+ * @hide
+ */
+ protected boolean persistStringSet(Set<String> values) {
+ if (shouldPersist()) {
+ // Shouldn't store null
+ if (values.equals(getPersistedStringSet(null))) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
+ editor.putStringSet(getKey(), values);
+ SharedPreferencesCompat.EditorCompat.getInstance().apply(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted set of Strings from the
+ * {@link android.content.SharedPreferences}.
+ * <p>
+ * This will check if this Preference is persistent, get the SharedPreferences
+ * from the {@link android.preference.PreferenceManager}, and get the value.
+ *
+ * @param defaultReturnValue The default value to return if either the
+ * Preference is not persistent or the Preference is not in the
+ * shared preferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #persistStringSet(Set)
+ *
+ * @hide
+ */
+ protected Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return getPreferenceManager().getSharedPreferences()
+ .getStringSet(getKey(), defaultReturnValue);
+ }
+
+ /**
+ * Sets the human-readable entries to be shown in the list. This will be
+ * shown in subsequent dialogs.
+ * <p>
+ * Each entry must have a corresponding index in
+ * {@link #setEntryValues(CharSequence[])}.
+ *
+ * @param entries The entries.
+ * @see #setEntryValues(CharSequence[])
+ */
+ public void setEntries(CharSequence[] entries) {
+ mEntries = entries;
+ }
+
+ /**
+ * @see #setEntries(CharSequence[])
+ * @param entriesResId The entries array as a resource.
+ */
+ public void setEntries(@ArrayRes int entriesResId) {
+ setEntries(getContext().getResources().getTextArray(entriesResId));
+ }
+
+ /**
+ * The list of entries to be shown in the list in subsequent dialogs.
+ *
+ * @return The list as an array.
+ */
+ public CharSequence[] getEntries() {
+ return mEntries;
+ }
+
+ /**
+ * The array to find the value to save for a preference when an entry from
+ * entries is selected. If a user clicks on the second item in entries, the
+ * second item in this array will be saved to the preference.
+ *
+ * @param entryValues The array to be used as values to save for the preference.
+ */
+ public void setEntryValues(CharSequence[] entryValues) {
+ mEntryValues = entryValues;
+ }
+
+ /**
+ * @see #setEntryValues(CharSequence[])
+ * @param entryValuesResId The entry values array as a resource.
+ */
+ public void setEntryValues(@ArrayRes int entryValuesResId) {
+ setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
+ }
+
+ /**
+ * Returns the array of values to be saved for the preference.
+ *
+ * @return The array of values.
+ */
+ public CharSequence[] getEntryValues() {
+ return mEntryValues;
+ }
+
+ /**
+ * Sets the value of the key. This should contain entries in
+ * {@link #getEntryValues()}.
+ *
+ * @param values The values to set for the key.
+ */
+ public void setValues(Set<String> values) {
+ mValues.clear();
+ mValues.addAll(values);
+
+ persistStringSet(values);
+ }
+
+ /**
+ * Retrieves the current value of the key.
+ */
+ public Set<String> getValues() {
+ return mValues;
+ }
+
+ /**
+ * Returns the index of the given value (in the entry values array).
+ *
+ * @param value The value whose index should be returned.
+ * @return The index of the value, or -1 if not found.
+ */
+ public int findIndexOfValue(String value) {
+ if (value != null && mEntryValues != null) {
+ for (int i = mEntryValues.length - 1; i >= 0; i--) {
+ if (mEntryValues[i].equals(value)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ protected boolean[] getSelectedItems() {
+ final CharSequence[] entries = mEntryValues;
+ final int entryCount = entries.length;
+ final Set<String> values = mValues;
+ boolean[] result = new boolean[entryCount];
+
+ for (int i = 0; i < entryCount; i++) {
+ result[i] = values.contains(entries[i].toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ final CharSequence[] defaultValues = a.getTextArray(index);
+ final Set<String> result = new HashSet<>();
+
+ for (final CharSequence defaultValue : defaultValues) {
+ result.add(defaultValue.toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setValues(restoreValue ? getPersistedStringSet(mValues) : (Set<String>) defaultValue);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ myState.values = getValues();
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setValues(myState.values);
+ }
+
+ private static class SavedState extends BaseSavedState {
+ Set<String> values;
+
+ public SavedState(Parcel source) {
+ super(source);
+ final int size = source.readInt();
+ values = new HashSet<>();
+ String[] strings = new String[size];
+ source.readStringArray(strings);
+
+ Collections.addAll(values, strings);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(values.size());
+ dest.writeStringArray(values.toArray(new String[values.size()]));
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
new file mode 100644
index 0000000..ec46aac
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/MultiSelectListPreferenceDialogFragment.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v14.preference;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class MultiSelectListPreferenceDialogFragment extends PreferenceDialogFragment {
+
+ private Set<String> mNewValues = new HashSet<>();
+ private boolean mPreferenceChanged;
+
+ public static MultiSelectListPreferenceDialogFragment newInstance(String key) {
+ final MultiSelectListPreferenceDialogFragment fragment =
+ new MultiSelectListPreferenceDialogFragment();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ private MultiSelectListPreference getListPreference() {
+ return (MultiSelectListPreference) getPreference();
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+
+ final MultiSelectListPreference preference = getListPreference();
+
+ if (preference.getEntries() == null || preference.getEntryValues() == null) {
+ throw new IllegalStateException(
+ "MultiSelectListPreference requires an entries array and " +
+ "an entryValues array.");
+ }
+
+ boolean[] checkedItems = preference.getSelectedItems();
+ builder.setMultiChoiceItems(preference.getEntries(), checkedItems,
+ new DialogInterface.OnMultiChoiceClickListener() {
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ if (isChecked) {
+ mPreferenceChanged |= mNewValues.add(
+ preference.getEntryValues()[which].toString());
+ } else {
+ mPreferenceChanged |= mNewValues.remove(
+ preference.getEntryValues()[which].toString());
+ }
+ }
+ });
+ mNewValues.clear();
+ mNewValues.addAll(preference.getValues());
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ final MultiSelectListPreference preference = getListPreference();
+ if (positiveResult && mPreferenceChanged) {
+ final Set<String> values = mNewValues;
+ if (preference.callChangeListener(values)) {
+ preference.setValues(values);
+ }
+ }
+ mPreferenceChanged = false;
+ }
+
+}
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java
new file mode 100644
index 0000000..b9027a4
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/PreferenceDialogFragment.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v14.preference;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.preference.DialogPreference;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+public abstract class PreferenceDialogFragment extends DialogFragment implements
+ DialogInterface.OnClickListener {
+
+ protected static final String ARG_KEY = "key";
+
+ private DialogPreference mPreference;
+
+ /** Which button was clicked. */
+ private int mWhichButtonClicked;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Fragment rawFragment = getTargetFragment();
+ if (!(rawFragment instanceof DialogPreference.TargetFragment)) {
+ throw new IllegalStateException("Target fragment must implement TargetFragment" +
+ " interface");
+ }
+
+ final DialogPreference.TargetFragment fragment =
+ (DialogPreference.TargetFragment) rawFragment;
+
+ final String key = getArguments().getString(ARG_KEY);
+ mPreference = (DialogPreference) fragment.findPreference(key);
+ }
+
+ @Override
+ public @NonNull
+ Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+ mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ .setTitle(mPreference.getDialogTitle())
+ .setIcon(mPreference.getDialogIcon())
+ .setPositiveButton(mPreference.getPositiveButtonText(), this)
+ .setNegativeButton(mPreference.getNegativeButtonText(), this);
+
+ View contentView = onCreateDialogView(context);
+ if (contentView != null) {
+ onBindDialogView(contentView);
+ builder.setView(contentView);
+ } else {
+ builder.setMessage(mPreference.getDialogMessage());
+ }
+
+ onPrepareDialogBuilder(builder);
+
+ // Create the dialog
+ final Dialog dialog = builder.create();
+ if (needInputMethod()) {
+ requestInputMethod(dialog);
+ }
+
+
+ return builder.create();
+ }
+
+ /**
+ * Get the preference that requested this dialog. Available after {@link #onCreate(Bundle)} has
+ * been called.
+ *
+ * @return The {@link DialogPreference} associated with this
+ * dialog.
+ */
+ public DialogPreference getPreference() {
+ return mPreference;
+ }
+
+ /**
+ * Prepares the dialog builder to be shown when the preference is clicked.
+ * Use this to set custom properties on the dialog.
+ * <p>
+ * Do not {@link AlertDialog.Builder#create()} or
+ * {@link AlertDialog.Builder#show()}.
+ */
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {}
+
+ /**
+ * Returns whether the preference needs to display a soft input method when the dialog
+ * is displayed. Default is false. Subclasses should override this method if they need
+ * the soft input method brought up automatically.
+ * @hide
+ */
+ protected boolean needInputMethod() {
+ return false;
+ }
+
+ /**
+ * Sets the required flags on the dialog window to enable input method window to show up.
+ */
+ private void requestInputMethod(Dialog dialog) {
+ Window window = dialog.getWindow();
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ }
+
+ /**
+ * Creates the content view for the dialog (if a custom content view is
+ * required). By default, it inflates the dialog layout resource if it is
+ * set.
+ *
+ * @return The content View for the dialog.
+ * @see DialogPreference#setLayoutResource(int)
+ */
+ protected View onCreateDialogView(Context context) {
+ final int resId = mPreference.getDialogLayoutResource();
+ if (resId == 0) {
+ return null;
+ }
+
+ LayoutInflater inflater = LayoutInflater.from(context);
+ return inflater.inflate(resId, null);
+ }
+
+ /**
+ * Binds views in the content View of the dialog to data.
+ * <p>
+ * Make sure to call through to the superclass implementation.
+ *
+ * @param view The content View of the dialog, if it is custom.
+ */
+ protected void onBindDialogView(View view) {
+ View dialogMessageView = view.findViewById(android.R.id.message);
+
+ if (dialogMessageView != null) {
+ final CharSequence message = mPreference.getDialogMessage();
+ int newVisibility = View.GONE;
+
+ if (!TextUtils.isEmpty(message)) {
+ if (dialogMessageView instanceof TextView) {
+ ((TextView) dialogMessageView).setText(message);
+ }
+
+ newVisibility = View.VISIBLE;
+ }
+
+ if (dialogMessageView.getVisibility() != newVisibility) {
+ dialogMessageView.setVisibility(newVisibility);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mWhichButtonClicked = which;
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
+ }
+
+ public abstract void onDialogClosed(boolean positiveResult);
+}
diff --git a/v14/preference/src/android/support/v14/preference/PreferenceFragment.java b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
new file mode 100644
index 0000000..a51dab3
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/PreferenceFragment.java
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v14.preference;
+
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.Nullable;
+import android.support.annotation.XmlRes;
+import android.support.v7.preference.DialogPreference;
+import android.support.v7.preference.EditTextPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroupAdapter;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Shows a hierarchy of {@link Preference} objects as
+ * lists. These preferences will
+ * automatically save to {@link android.content.SharedPreferences} as the user interacts with
+ * them. To retrieve an instance of {@link android.content.SharedPreferences} that the
+ * preference hierarchy in this fragment will use, call
+ * {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)}
+ * with a context in the same package as this fragment.
+ * <p>
+ * Furthermore, the preferences shown will follow the visual style of system
+ * preferences. It is easy to create a hierarchy of preferences (that can be
+ * shown on multiple screens) via XML. For these reasons, it is recommended to
+ * use this fragment (as a superclass) to deal with preferences in applications.
+ * <p>
+ * A {@link PreferenceScreen} object should be at the top of the preference
+ * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
+ * denote a screen break--that is the preferences contained within subsequent
+ * {@link PreferenceScreen} should be shown on another screen. The preference
+ * framework handles showing these other screens from the preference hierarchy.
+ * <p>
+ * The preference hierarchy can be formed in multiple ways:
+ * <li> From an XML file specifying the hierarchy
+ * <li> From different {@link android.app.Activity Activities} that each specify its own
+ * preferences in an XML file via {@link android.app.Activity} meta-data
+ * <li> From an object hierarchy rooted with {@link PreferenceScreen}
+ * <p>
+ * To inflate from XML, use the {@link #addPreferencesFromResource(int)}. The
+ * root element should be a {@link PreferenceScreen}. Subsequent elements can point
+ * to actual {@link Preference} subclasses. As mentioned above, subsequent
+ * {@link PreferenceScreen} in the hierarchy will result in the screen break.
+ * <p>
+ * To specify an object hierarchy rooted with {@link PreferenceScreen}, use
+ * {@link #setPreferenceScreen(PreferenceScreen)}.
+ * <p>
+ * As a convenience, this fragment implements a click listener for any
+ * preference in the current hierarchy, see
+ * {@link #onPreferenceTreeClick(Preference)}.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about using {@code PreferenceFragment},
+ * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
+ * guide.</p>
+ * </div>
+ *
+ * <a name="SampleCode"></a>
+ * <h3>Sample Code</h3>
+ *
+ * <p>The following sample code shows a simple preference fragment that is
+ * populated from a resource. The resource it loads is:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/xml/preferences.xml preferences}
+ *
+ * <p>The fragment implementation itself simply populates the preferences
+ * when created. Note that the preferences framework takes care of loading
+ * the current values out of the app preferences and writing them when changed:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/FragmentPreferences.java
+ * fragment}
+ *
+ * @see Preference
+ * @see PreferenceScreen
+ */
+public abstract class PreferenceFragment extends Fragment implements
+ PreferenceManager.OnPreferenceTreeClickListener,
+ PreferenceManager.OnDisplayPreferenceDialogListener,
+ PreferenceManager.OnNavigateToScreenListener,
+ DialogPreference.TargetFragment {
+
+ /**
+ * Fragment argument used to specify the tag of the desired root
+ * {@link android.support.v7.preference.PreferenceScreen} object.
+ */
+ public static final String ARG_PREFERENCE_ROOT =
+ "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+
+ private static final String PREFERENCES_TAG = "android:preferences";
+
+ private static final String DIALOG_FRAGMENT_TAG =
+ "android.support.v14.preference.PreferenceFragment.DIALOG";
+
+ private PreferenceManager mPreferenceManager;
+ private RecyclerView mList;
+ private boolean mHavePrefs;
+ private boolean mInitDone;
+
+ private Context mStyledContext;
+
+ private int mLayoutResId = R.layout.preference_list_fragment;
+
+ /**
+ * The starting request code given out to preference framework.
+ */
+ private static final int FIRST_REQUEST_CODE = 100;
+
+ private static final int MSG_BIND_PREFERENCES = 1;
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+
+ case MSG_BIND_PREFERENCES:
+ bindPreferences();
+ break;
+ }
+ }
+ };
+
+ final private Runnable mRequestFocus = new Runnable() {
+ public void run() {
+ mList.focusableViewAvailable(mList);
+ }
+ };
+
+ /**
+ * Interface that PreferenceFragment's containing activity should
+ * implement to be able to process preference items that wish to
+ * switch to a specified fragment.
+ */
+ public interface OnPreferenceStartFragmentCallback {
+ /**
+ * Called when the user has clicked on a Preference that has
+ * a fragment class name associated with it. The implementation
+ * should instantiate and switch to an instance of the given
+ * fragment.
+ * @param caller The fragment requesting navigation.
+ * @param pref The preference requesting the fragment.
+ * @return true if the fragment creation has been handled
+ */
+ boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref);
+ }
+
+ /**
+ * Interface that PreferenceFragment's containing activity should
+ * implement to be able to process preference items that wish to
+ * switch to a new screen of preferences.
+ */
+ public interface OnPreferenceStartScreenCallback {
+ /**
+ * Called when the user has clicked on a PreferenceScreen item in order to navigate to a new
+ * screen of preferences.
+ * @param caller The fragment requesting navigation.
+ * @param pref The preference screen to navigate to.
+ * @return true if the screen navigation has been handled
+ */
+ boolean onPreferenceStartScreen(PreferenceFragment caller, PreferenceScreen pref);
+ }
+
+ public interface OnPreferenceDisplayDialogCallback {
+
+ /**
+ *
+ * @param caller The fragment containing the preference requesting the dialog.
+ * @param pref The preference requesting the dialog.
+ * @return true if the dialog creation has been handled.
+ */
+ boolean onPreferenceDisplayDialog(PreferenceFragment caller, Preference pref);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final TypedValue tv = new TypedValue();
+ getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
+ final int theme = tv.resourceId;
+ if (theme <= 0) {
+ throw new IllegalStateException("Must specify preferenceTheme in theme");
+ }
+ mStyledContext = new ContextThemeWrapper(getActivity(), theme);
+
+ mPreferenceManager = new PreferenceManager(mStyledContext);
+ mPreferenceManager.setOnNavigateToScreenListener(this);
+ final Bundle args = getArguments();
+ final String rootKey;
+ if (args != null) {
+ rootKey = getArguments().getString(ARG_PREFERENCE_ROOT);
+ } else {
+ rootKey = null;
+ }
+ onCreatePreferences(savedInstanceState, rootKey);
+ }
+
+ /**
+ * Called during {@link #onCreate(Bundle)} to supply the preferences for this fragment.
+ * Subclasses are expected to call {@link #setPreferenceScreen(PreferenceScreen)} either
+ * directly or via helper methods such as {@link #addPreferencesFromResource(int)}.
+ *
+ * @param savedInstanceState If the fragment is being re-created from
+ * a previous saved state, this is the state.
+ * @param rootKey If non-null, this preference fragment should be rooted at the
+ * {@link android.support.v7.preference.PreferenceScreen} with this key.
+ */
+ public abstract void onCreatePreferences(Bundle savedInstanceState, String rootKey);
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ TypedArray a = mStyledContext.obtainStyledAttributes(null,
+ R.styleable.PreferenceFragmentCompat,
+ R.attr.preferenceFragmentStyle,
+ 0);
+
+ mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
+ mLayoutResId);
+
+ a.recycle();
+
+ final View view = inflater.inflate(mLayoutResId, container, false);
+
+ final View rawListContainer = view.findViewById(R.id.list_container);
+ if (!(rawListContainer instanceof ViewGroup)) {
+ throw new RuntimeException("Content has view with id attribute 'R.id.list_container' "
+ + "that is not a ViewGroup class");
+ }
+
+ final ViewGroup listContainer = (ViewGroup) rawListContainer;
+
+ final RecyclerView listView = onCreateRecyclerView(inflater, listContainer,
+ savedInstanceState);
+ if (listView == null) {
+ throw new RuntimeException("Could not create RecyclerView");
+ }
+
+ mList = listView;
+ listContainer.addView(mList);
+ mHandler.post(mRequestFocus);
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (mHavePrefs) {
+ bindPreferences();
+ }
+
+ mInitDone = true;
+
+ if (savedInstanceState != null) {
+ Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
+ if (container != null) {
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ preferenceScreen.restoreHierarchyState(container);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mPreferenceManager.setOnPreferenceTreeClickListener(this);
+ mPreferenceManager.setOnDisplayPreferenceDialogListener(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mPreferenceManager.setOnPreferenceTreeClickListener(null);
+ mPreferenceManager.setOnDisplayPreferenceDialogListener(null);
+ }
+
+ @Override
+ public void onDestroyView() {
+ mList = null;
+ mHandler.removeCallbacks(mRequestFocus);
+ mHandler.removeMessages(MSG_BIND_PREFERENCES);
+ super.onDestroyView();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ Bundle container = new Bundle();
+ preferenceScreen.saveHierarchyState(container);
+ outState.putBundle(PREFERENCES_TAG, container);
+ }
+ }
+
+ /**
+ * Returns the {@link PreferenceManager} used by this fragment.
+ * @return The {@link PreferenceManager}.
+ */
+ public PreferenceManager getPreferenceManager() {
+ return mPreferenceManager;
+ }
+
+ /**
+ * Sets the root of the preference hierarchy that this fragment is showing.
+ *
+ * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
+ */
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
+ onUnbindPreferences();
+ mHavePrefs = true;
+ if (mInitDone) {
+ postBindPreferences();
+ }
+ }
+ }
+
+ /**
+ * Gets the root of the preference hierarchy that this fragment is showing.
+ *
+ * @return The {@link PreferenceScreen} that is the root of the preference
+ * hierarchy.
+ */
+ public PreferenceScreen getPreferenceScreen() {
+ return mPreferenceManager.getPreferenceScreen();
+ }
+
+ /**
+ * Inflates the given XML resource and adds the preference hierarchy to the current
+ * preference hierarchy.
+ *
+ * @param preferencesResId The XML resource ID to inflate.
+ */
+ public void addPreferencesFromResource(@XmlRes int preferencesResId) {
+ requirePreferenceManager();
+
+ setPreferenceScreen(mPreferenceManager.inflateFromResource(mStyledContext,
+ preferencesResId, getPreferenceScreen()));
+ }
+
+ /**
+ * Inflates the given XML resource and replaces the current preference hierarchy (if any) with
+ * the preference hierarchy rooted at {@code key}.
+ *
+ * @param preferencesResId The XML resource ID to inflate.
+ * @param key The preference key of the {@link android.support.v7.preference.PreferenceScreen}
+ * to use as the root of the preference hierarchy, or null to use the root
+ * {@link android.support.v7.preference.PreferenceScreen}.
+ */
+ public void setPreferencesFromResource(@XmlRes int preferencesResId, @Nullable String key) {
+ requirePreferenceManager();
+
+ final PreferenceScreen xmlRoot = mPreferenceManager.inflateFromResource(mStyledContext,
+ preferencesResId, null);
+
+ final Preference root;
+ if (key != null) {
+ root = xmlRoot.findPreference(key);
+ if (!(root instanceof PreferenceScreen)) {
+ throw new IllegalArgumentException("Preference object with key " + key
+ + " is not a PreferenceScreen");
+ }
+ } else {
+ root = xmlRoot;
+ }
+
+ setPreferenceScreen((PreferenceScreen) root);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean onPreferenceTreeClick(Preference preference) {
+ if (preference.getFragment() != null) {
+ boolean handled = false;
+ if (getTargetFragment() instanceof OnPreferenceStartFragmentCallback) {
+ handled = ((OnPreferenceStartFragmentCallback) getTargetFragment())
+ .onPreferenceStartFragment(this, preference);
+ }
+ if (!handled && getActivity() instanceof OnPreferenceStartFragmentCallback){
+ handled = ((OnPreferenceStartFragmentCallback) getActivity())
+ .onPreferenceStartFragment(this, preference);
+ }
+ return handled;
+ }
+ return false;
+ }
+
+ /**
+ * Called by
+ * {@link android.support.v7.preference.PreferenceScreen#onClick()} in order to navigate to a
+ * new screen of preferences. Calls
+ * {@link PreferenceFragment.OnPreferenceStartScreenCallback#onPreferenceStartScreen}
+ * if the target fragment or containing activity implements
+ * {@link PreferenceFragment.OnPreferenceStartScreenCallback}.
+ * @param preferenceScreen The {@link android.support.v7.preference.PreferenceScreen} to
+ * navigate to.
+ */
+ @Override
+ public void onNavigateToScreen(PreferenceScreen preferenceScreen) {
+ boolean handled = false;
+ if (getTargetFragment() instanceof OnPreferenceStartScreenCallback) {
+ handled = ((OnPreferenceStartScreenCallback) getTargetFragment())
+ .onPreferenceStartScreen(this, preferenceScreen);
+ }
+ if (!handled && getActivity() instanceof OnPreferenceStartScreenCallback) {
+ ((OnPreferenceStartScreenCallback) getActivity())
+ .onPreferenceStartScreen(this, preferenceScreen);
+ }
+ }
+
+ /**
+ * Finds a {@link Preference} based on its key.
+ *
+ * @param key The key of the preference to retrieve.
+ * @return The {@link Preference} with the key, or null.
+ * @see android.support.v7.preference.PreferenceGroup#findPreference(CharSequence)
+ */
+ public Preference findPreference(CharSequence key) {
+ if (mPreferenceManager == null) {
+ return null;
+ }
+ return mPreferenceManager.findPreference(key);
+ }
+
+ private void requirePreferenceManager() {
+ if (mPreferenceManager == null) {
+ throw new RuntimeException("This should be called after super.onCreate.");
+ }
+ }
+
+ private void postBindPreferences() {
+ if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
+ mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
+ }
+
+ private void bindPreferences() {
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ getListView().setAdapter(onCreateAdapter(preferenceScreen));
+ }
+ onBindPreferences();
+ }
+
+ /** @hide */
+ protected void onBindPreferences() {
+ }
+
+ /** @hide */
+ protected void onUnbindPreferences() {
+ }
+
+ public final RecyclerView getListView() {
+ return mList;
+ }
+
+ /**
+ * Creates the {@link android.support.v7.widget.RecyclerView} used to display the preferences.
+ * Subclasses may override this to return a customized
+ * {@link android.support.v7.widget.RecyclerView}.
+ * @param inflater The LayoutInflater object that can be used to inflate the
+ * {@link android.support.v7.widget.RecyclerView}.
+ * @param parent The parent {@link android.view.View} that the RecyclerView will be attached to.
+ * This method should not add the view itself, but this can be used to generate
+ * the LayoutParams of the view.
+ * @param savedInstanceState If non-null, this view is being re-constructed from a previous
+ * saved state as given here
+ * @return A new RecyclerView object to be placed into the view hierarchy
+ */
+ public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+ Bundle savedInstanceState) {
+ RecyclerView recyclerView = (RecyclerView) inflater
+ .inflate(R.layout.preference_recyclerview, parent, false);
+
+ recyclerView.setLayoutManager(onCreateLayoutManager());
+
+ return recyclerView;
+ }
+
+ /**
+ * Called from {@link #onCreateRecyclerView} to create the
+ * {@link android.support.v7.widget.RecyclerView.LayoutManager} for the created
+ * {@link android.support.v7.widget.RecyclerView}.
+ * @return A new {@link android.support.v7.widget.RecyclerView.LayoutManager} instance.
+ */
+ public RecyclerView.LayoutManager onCreateLayoutManager() {
+ return new LinearLayoutManager(getActivity());
+ }
+
+ /**
+ * Creates the root adapter.
+ *
+ * @param preferenceScreen Preference screen object to create the adapter for.
+ * @return An adapter that contains the preferences contained in this {@link PreferenceScreen}.
+ */
+ protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
+ return new PreferenceGroupAdapter(preferenceScreen);
+ }
+
+ /**
+ * Called when a preference in the tree requests to display a dialog. Subclasses should
+ * override this method to display custom dialogs or to handle dialogs for custom preference
+ * classes.
+ *
+ * @param preference The Preference object requesting the dialog.
+ */
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+
+ boolean handled = false;
+ if (getTargetFragment() instanceof OnPreferenceDisplayDialogCallback) {
+ handled = ((OnPreferenceDisplayDialogCallback) getTargetFragment())
+ .onPreferenceDisplayDialog(this, preference);
+ }
+ if (!handled && getActivity() instanceof OnPreferenceDisplayDialogCallback) {
+ handled = ((OnPreferenceDisplayDialogCallback) getActivity())
+ .onPreferenceDisplayDialog(this, preference);
+ }
+
+ if (handled) {
+ return;
+ }
+
+ // check if dialog is already showing
+ if (getFragmentManager().findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {
+ return;
+ }
+
+ final DialogFragment f;
+ if (preference instanceof EditTextPreference) {
+ f = EditTextPreferenceDialogFragment.newInstance(preference.getKey());
+ } else if (preference instanceof ListPreference) {
+ f = ListPreferenceDialogFragment.newInstance(preference.getKey());
+ } else if (preference instanceof MultiSelectListPreference) {
+ f = MultiSelectListPreferenceDialogFragment.newInstance(preference.getKey());
+ } else {
+ throw new IllegalArgumentException("Tried to display dialog for unknown " +
+ "preference type. Did you forget to override onDisplayPreferenceDialog()?");
+ }
+ f.setTargetFragment(this, 0);
+ f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
+ }
+
+}
diff --git a/v14/preference/src/android/support/v14/preference/SwitchPreference.java b/v14/preference/src/android/support/v14/preference/SwitchPreference.java
new file mode 100644
index 0000000..048bc6c
--- /dev/null
+++ b/v14/preference/src/android/support/v14/preference/SwitchPreference.java
@@ -0,0 +1,214 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+package android.support.v14.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.support.v7.preference.TwoStatePreference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+
+/**
+ * A {@link android.support.v7.preference.Preference} that provides a two-state toggleable option.
+ * <p>
+ * This preference will store a boolean into the SharedPreferences.
+ *
+ * @attr ref android.R.styleable#SwitchPreference_summaryOff
+ * @attr ref android.R.styleable#SwitchPreference_summaryOn
+ * @attr ref android.R.styleable#SwitchPreference_switchTextOff
+ * @attr ref android.R.styleable#SwitchPreference_switchTextOn
+ * @attr ref android.R.styleable#SwitchPreference_disableDependentsState
+ */
+public class SwitchPreference extends TwoStatePreference {
+ private final Listener mListener = new Listener();
+
+ // Switch text for on and off states
+ private CharSequence mSwitchOn;
+ private CharSequence mSwitchOff;
+
+ private class Listener implements CompoundButton.OnCheckedChangeListener {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (!callChangeListener(isChecked)) {
+ // Listener didn't like it, change it back.
+ // CompoundButton will make sure we don't recurse.
+ buttonView.setChecked(!isChecked);
+ return;
+ }
+
+ SwitchPreference.this.setChecked(isChecked);
+ }
+ }
+
+ /**
+ * Construct a new SwitchPreference with the given style options.
+ *
+ * @param context The Context that will style this preference
+ * @param attrs Style attributes that differ from the default
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ * @param defStyleRes A resource identifier of a style resource that
+ * supplies default values for the view, used only if
+ * defStyleAttr is 0 or can not be found in the theme. Can be 0
+ * to not look for defaults.
+ */
+ public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.SwitchPreference, defStyleAttr, defStyleRes);
+
+ setSummaryOn(TypedArrayUtils.getString(a, R.styleable.SwitchPreference_summaryOn,
+ R.styleable.SwitchPreference_android_summaryOn));
+
+ setSummaryOff(TypedArrayUtils.getString(a, R.styleable.SwitchPreference_summaryOff,
+ R.styleable.SwitchPreference_android_summaryOff));
+
+ setSwitchTextOn(TypedArrayUtils.getString(a,
+ R.styleable.SwitchPreference_switchTextOn,
+ R.styleable.SwitchPreference_android_switchTextOn));
+
+ setSwitchTextOff(TypedArrayUtils.getString(a,
+ R.styleable.SwitchPreference_switchTextOff,
+ R.styleable.SwitchPreference_android_switchTextOff));
+
+ setDisableDependentsState(TypedArrayUtils.getBoolean(a,
+ R.styleable.SwitchPreference_disableDependentsState,
+ R.styleable.SwitchPreference_android_disableDependentsState, false));
+
+ a.recycle();
+ }
+
+ /**
+ * Construct a new SwitchPreference with the given style options.
+ *
+ * @param context The Context that will style this preference
+ * @param attrs Style attributes that differ from the default
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ */
+ public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ /**
+ * Construct a new SwitchPreference with the given style options.
+ *
+ * @param context The Context that will style this preference
+ * @param attrs Style attributes that differ from the default
+ */
+ public SwitchPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.switchPreferenceStyle);
+ }
+
+ /**
+ * Construct a new SwitchPreference with default style options.
+ *
+ * @param context The Context that will style this preference
+ */
+ public SwitchPreference(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View checkableView = holder.findViewById(R.id.switchWidget);
+ if (checkableView != null && checkableView instanceof Checkable) {
+ if (checkableView instanceof Switch) {
+ final Switch switchView = (Switch) checkableView;
+ switchView.setOnCheckedChangeListener(null);
+ }
+
+ ((Checkable) checkableView).setChecked(mChecked);
+
+ if (checkableView instanceof Switch) {
+ final Switch switchView = (Switch) checkableView;
+ switchView.setTextOn(mSwitchOn);
+ switchView.setTextOff(mSwitchOff);
+ switchView.setOnCheckedChangeListener(mListener);
+ }
+ }
+
+ syncSummaryView(holder);
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the on state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param onText Text to display in the on state
+ */
+ public void setSwitchTextOn(CharSequence onText) {
+ mSwitchOn = onText;
+ notifyChanged();
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the off state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param offText Text to display in the off state
+ */
+ public void setSwitchTextOff(CharSequence offText) {
+ mSwitchOff = offText;
+ notifyChanged();
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the on state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param resId The text as a string resource ID
+ */
+ public void setSwitchTextOn(int resId) {
+ setSwitchTextOn(getContext().getString(resId));
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the off state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param resId The text as a string resource ID
+ */
+ public void setSwitchTextOff(int resId) {
+ setSwitchTextOff(getContext().getString(resId));
+ }
+
+ /**
+ * @return The text that will be displayed on the switch widget in the on state
+ */
+ public CharSequence getSwitchTextOn() {
+ return mSwitchOn;
+ }
+
+ /**
+ * @return The text that will be displayed on the switch widget in the off state
+ */
+ public CharSequence getSwitchTextOff() {
+ return mSwitchOff;
+ }
+}
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index 336a422..0dd5831 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -504,6 +504,22 @@
}
+package android.support.v17.leanback.view {
+
+ public class ViewGroupOverlayHelper {
+ ctor public ViewGroupOverlayHelper();
+ method public static void addChildToOverlay(android.view.ViewGroup, android.view.View);
+ method public static void removeChildFromOverlay(android.view.ViewGroup, android.view.View);
+ method public static boolean supportsOverlay();
+ }
+
+ public static abstract interface ViewGroupOverlayHelper.Impl {
+ method public abstract void addChildToOverlay(android.view.ViewGroup, android.view.View);
+ method public abstract void removeChildFromOverlay(android.view.ViewGroup, android.view.View);
+ }
+
+}
+
package android.support.v17.leanback.widget {
public abstract class AbstractDetailsDescriptionPresenter extends android.support.v17.leanback.widget.Presenter {
diff --git a/v17/leanback/build.gradle b/v17/leanback/build.gradle
index b34e2a1..8dc79e8 100644
--- a/v17/leanback/build.gradle
+++ b/v17/leanback/build.gradle
@@ -27,6 +27,11 @@
androidTest.java.srcDir 'tests/java'
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
lintOptions {
// TODO: fix errors and reenable.
abortOnError false
diff --git a/v17/leanback/jbmr2/android/support/v17/leanback/view/ViewGroupOverlayHelperJbmr2.java b/v17/leanback/jbmr2/android/support/v17/leanback/view/ViewGroupOverlayHelperJbmr2.java
new file mode 100644
index 0000000..12dda9a
--- /dev/null
+++ b/v17/leanback/jbmr2/android/support/v17/leanback/view/ViewGroupOverlayHelperJbmr2.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.leanback.view;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ViewGroupOverlayHelperJbmr2 {
+
+ public static void addChildToOverlay(ViewGroup parent, View child) {
+ parent.getOverlay().add(child);
+ }
+
+ public static void removeChildFromOverlay(ViewGroup parent, View child) {
+ parent.getOverlay().remove(child);
+ }
+}
diff --git a/v17/leanback/res/values-af/strings.xml b/v17/leanback/res/values-af/strings.xml
index fa93257..c7109bb 100644
--- a/v17/leanback/res/values-af/strings.xml
+++ b/v17/leanback/res/values-af/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Praat om te soek"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Deursoek <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Praat om <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> te deursoek"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Speel"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Laat wag"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Vinnig vorentoe"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spoel vorentoe %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spoel terug"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spoel terug %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Slaan volgende oor"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Slaan vorige oor"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Nog handelinge"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ontkies laaik baie"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Kies laaik baie"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Ontkies laaik niks"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Kies laaik niks"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Herhaal niks"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Herhaal alles"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Herhaal een"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktiveer skommel"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Deaktiveer skommel"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktiveer hoë gehalte"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiveer hoë gehalte"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktiveer onderskrifte"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiveer onderskrifte"</string>
</resources>
diff --git a/v17/leanback/res/values-am/strings.xml b/v17/leanback/res/values-am/strings.xml
index 4b0f26f..d5bf0f5 100644
--- a/v17/leanback/res/values-am/strings.xml
+++ b/v17/leanback/res/values-am/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ለመፈለግ ይናገሩ"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ፈልግ"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ን ለመፈለግ ይናገሩ"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"አጫውት"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ለአፍታ አቁም"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"በፍጥነት አሳልፍ"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"በ%1$dX ወደፊት አፍጥን"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ወደኋላ አጠንጥን"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"በ%1$dX አጠንጥን"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"የሚቀጥለውን ዝለል"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"የቀደመውን ዝለል"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"ተጨማሪ እርምጃዎች"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"አውራጣት ወደ ላይን አትምረጥ"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"አውራ ጣት ወደላይን ምረጥ"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"አውራ ጣት ወደታችን አትምረጥ"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"አውራ ጣት ወደታችን ምረጥ"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ምንም አትድገም"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ሁሉንም ድገም"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"አንዱን ድገም"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"መበወዣን አንቃ"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"መበወዣን አሰናክል"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ከፍተኛ ጥራትን አንቃ"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ከፍተኛ ጥራትን አሰናክል"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አንቃ"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ዝግ የምስል ስር ጽሑፍ አጻጻፍን አሰናክል"</string>
</resources>
diff --git a/v17/leanback/res/values-ar/strings.xml b/v17/leanback/res/values-ar/strings.xml
index 6540a3e..31f4d1a 100644
--- a/v17/leanback/res/values-ar/strings.xml
+++ b/v17/leanback/res/values-ar/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"التحدث للبحث"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"بحث في <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"تحدّث للبحث في <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"تشغيل"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"إيقاف مؤقت"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"تقديم سريع"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"التقديم السريع %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"إرجاع"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"الترجيع %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"تخطي التالي"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"تخطي السابق"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"مزيد من الإجراءات"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"إلغاء تحديد زر \"أعجبني\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"تحديد زر \"أعجبني\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"إلغاء تحديد زر \"لم يعجبني\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"تحديد زر \"لم يعجبني\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"عدم التكرار"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"تكرار الكل"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"تكرار مقطع واحد"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"تمكين الترتيب العشوائي"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"تعطيل الترتيب العشوائي"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"تمكين الجودة العالية"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"تعطيل الجودة العالية"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"تمكين الترجمة المصاحبة"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"تعطيل الترجمة المصاحبة"</string>
</resources>
diff --git a/v17/leanback/res/values-az-rAZ/strings.xml b/v17/leanback/res/values-az-rAZ/strings.xml
new file mode 100644
index 0000000..d1e685f
--- /dev/null
+++ b/v17/leanback/res/values-az-rAZ/strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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="orb_search_action" msgid="5651268540267663887">"Axtarış Fəaliyyəti"</string>
+ <string name="lb_search_bar_hint" msgid="8325490927970116252">"Axtarış"</string>
+ <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Axtarış üçün danışın"</string>
+ <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Axtarış: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Axtarış üçün danışın: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Oyun"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauza"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"İrəli Ötürmə"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"İrəli sarı %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Geri ötürmə"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Geri sarı %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Növbətini atlayın"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Öncəkini atlayın"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Digər fəaliyyətlər"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Bəyənməkdən imtina edin"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Bəyənin"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Bəyənməməkdən imtina edin"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Bəyənməyin"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Təkrarlanmasın"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Hamısını təkrarlayın"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Biri təkrarlansın"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Qarışdırma aktiv edilsin"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Qarışdırma deaktiv edilsin"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Yüksək keyfiyyəti aktiv edin"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksək keyfiyyəti deaktiv edin"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Qapalı çəkilişi aktiv edin"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Qapalı çəkilişi deaktiv edin"</string>
+</resources>
diff --git a/v17/leanback/res/values-bg/strings.xml b/v17/leanback/res/values-bg/strings.xml
index 9cd9b5c..de0b6f8 100644
--- a/v17/leanback/res/values-bg/strings.xml
+++ b/v17/leanback/res/values-bg/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Говорете, за да търсите"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Търсете в/ъв <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Говорете, за да търсите в/ъв <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Пускане"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Поставяне на пауза"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Превъртане напред"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Превъртане напред със скорост %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Превъртане назад"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Превъртане назад със скорост %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Напред към следващия елемент"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Назад към предишния елемент"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Още действия"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Премахване на избора от „Харесва ми“"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Избиране на „Харесва ми“"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Премахване на избора от „Не ми харесва“"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Избиране на „Не ми харесва“"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Без повтаряне"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Повтаряне на всички"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Повтаряне на един елемент"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Активиране на разбъркването"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Деактивиране на разбъркването"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Активиране на високото качество"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Деактивиране на високото качество"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Активиране на субтитрите"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Деактивиране на субтитрите"</string>
</resources>
diff --git a/v17/leanback/res/values-bn-rBD/strings.xml b/v17/leanback/res/values-bn-rBD/strings.xml
index 400553a..4f0526c 100644
--- a/v17/leanback/res/values-bn-rBD/strings.xml
+++ b/v17/leanback/res/values-bn-rBD/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"অনুসন্ধান করতে বলুন"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> অনুসন্ধান করুন"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> অনুসন্ধান করতে বলুন"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"চালান"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"বিরাম দিন"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"দ্রুত ফরওয়ার্ড"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"দ্রুত ফরওয়ার্ড %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"পেছনের দিকে যান"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"পেছনের দিকে যান %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"সরাসরি পরেরটিতে চলে যান"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"সরাসরি আগেরটিতে চলে যান"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"আরো অ্যাকশন"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"উপরের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচন মুক্ত করুন"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"উপরের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচিত করুন"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"নীচের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচন মুক্ত করুন"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"নীচের দিকে বুড়ো আঙ্গুল নির্দেশিত চিহ্ন নির্বাচন করুন"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"একটিরও পুনরাবৃত্তি করবেন না"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"সবগুলির পুনরাবৃত্তি করুন"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"একটির পুনরাবৃত্তি করুন"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"শাফল করা সক্ষম করুন"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"শাফল করা অক্ষম করুন"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"উচ্চ গুণমান সক্ষম করুন"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"উচ্চ গুণমান অক্ষম করুন"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"সাবটাইটেল সক্ষম করুন"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"সাবটাইটেল অক্ষম করুন"</string>
</resources>
diff --git a/v17/leanback/res/values-ca/strings.xml b/v17/leanback/res/values-ca/strings.xml
index 9087b56..187f5af 100644
--- a/v17/leanback/res/values-ca/strings.xml
+++ b/v17/leanback/res/values-ca/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Parla per fer una cerca."</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Cerca a <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>."</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Parla per cercar a <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>."</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reprodueix"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Posa en pausa"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avança ràpidament"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avança ràpidament %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rebobina"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobina %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Passa al següent"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Passa a l\'anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Més accions"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Anul·la \"M\'agrada\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Selecciona \"M\'agrada\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Anul·la \"No m\'agrada\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Selecciona \"M\'agrada\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"No en repeteixis cap"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeteix-ho tot"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeteix-ne un"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activa la reproducció aleatòria"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desactiva la reproducció aleatòria"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activa l\'alta qualitat"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactiva l\'alta qualitat"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activa els subtítols tancats"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactiva els subtítols tancats"</string>
</resources>
diff --git a/v17/leanback/res/values-cs/strings.xml b/v17/leanback/res/values-cs/strings.xml
index 7c5b18c..1a60828 100644
--- a/v17/leanback/res/values-cs/strings.xml
+++ b/v17/leanback/res/values-cs/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Vyhledávání"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Vyhledávejte hlasem"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Hledat <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vyhledávejte v kontextu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> hlasem"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vyhledávejte v kategorii „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“ hlasem"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d×"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d×"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Přehrát"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pozastavit"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Přetočit vpřed"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Přetočit vpřed %1$d×"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Přetočit zpět"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Přetočit zpět %1$d×"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Přeskočit na další"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Přeskočit na předchozí"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Další akce"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Zrušit výběr hodnocení palec nahoru"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vybrat hodnocení palec nahoru"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Zrušit výběr hodnocení palec dolů"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vybrat hodnocení palec dolů"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Neopakovat"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Opakovat vše"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Opakovat jednu položku"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Zapnout náhodné přehrávání"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Vypnout náhodné přehrávání"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Zapnout vysokou kvalitu"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Vypnout vysokou kvalitu"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnout titulky"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnout titulky"</string>
</resources>
diff --git a/v17/leanback/res/values-da/strings.xml b/v17/leanback/res/values-da/strings.xml
index 51a195a..e3e0f9f 100644
--- a/v17/leanback/res/values-da/strings.xml
+++ b/v17/leanback/res/values-da/strings.xml
@@ -17,9 +17,33 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="orb_search_action" msgid="5651268540267663887">"Søgehandling"</string>
+ <string name="orb_search_action" msgid="5651268540267663887">"Søg handling"</string>
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Søg"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tal for at søge"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Søg efter <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Tal for at søge efter <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Afspil"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Sæt på pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Spol frem"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spol frem %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spol tilbage"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spol tilbage %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Spring til næste"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Spring til forrige"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Flere handlinger"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Fravælg tommelfinger op"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vælg tommelfinger op"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Fravælg tommelfinger ned"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vælg tommelfinger ned"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Gentag ingen"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Gentag alle"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Gentag en"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktivér bland"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Deaktiver bland"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivér høj aktivitet"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høj kvalitet"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér undertekster"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver undertekster"</string>
</resources>
diff --git a/v17/leanback/res/values-de/strings.xml b/v17/leanback/res/values-de/strings.xml
index 1b353a0..d729f7c 100644
--- a/v17/leanback/res/values-de/strings.xml
+++ b/v17/leanback/res/values-de/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Suchen"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Zum Suchen sprechen"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"In <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> suchen"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Zum Suchen in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> sprechen"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Zum Suchen in der Kategorie \"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>\" sprechen"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dx"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dx"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Wiedergabe"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausieren"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Vorspulen"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Vorspulen %1$dx"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Zurückspulen"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Zurückspulen %1$dx"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Nächsten Titel überspringen"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Vorherigen Titel überspringen"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Weitere Aktionen"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"\"Mag ich\" deaktivieren"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"\"Mag ich\" aktivieren"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"\"Mag ich nicht\" deaktivieren"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"\"Mag ich nicht\" aktivieren"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Keinen Titel wiederholen"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Alle wiederholen"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Einen Titel wiederholen"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Zufallsmix aktivieren"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Zufallsmix deaktivieren"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Hohe Qualität aktivieren"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hohe Qualität deaktivieren"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Untertitel aktivieren"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Untertitel deaktivieren"</string>
</resources>
diff --git a/v17/leanback/res/values-el/strings.xml b/v17/leanback/res/values-el/strings.xml
index fc8c159..9b93dcf 100644
--- a/v17/leanback/res/values-el/strings.xml
+++ b/v17/leanback/res/values-el/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Μιλήστε για να κάνετε αναζήτηση"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Αναζήτηση <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Μιλήστε για αναζήτηση <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Αναπαραγωγή"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Παύση"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Γρήγορη προώθηση"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Γρήγορη προώθηση %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Επαναφορά"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Επαναφορά %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Παράβλεψη επόμενου"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Παράβλεψη προηγούμενου"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Περισσότερες ενέργειες"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Κατάργηση επιλογής \"Μου αρέσουν\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Επιλογή \"Μου αρέσουν\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Κατάργηση επιλογής \"Δεν μου αρέσουν\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Επιλογή \"Δεν μου αρέσουν\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Καμία επανάληψη"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Επανάληψη όλων"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Επανάληψη ενός στοιχείου"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ενεργοποίηση Τυχαίας αναπαραγωγής"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Απενεργοποίηση Τυχαίας αναπαραγωγής"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ενεργοποίηση Υψηλής ποιότητας"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Απενεργοποίηση Υψηλής ποιότητας"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ενεργοποίηση υποτίτλων"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Απενεργοποίηση υποτίτλων"</string>
</resources>
diff --git a/v17/leanback/res/values-en-rAU/strings.xml b/v17/leanback/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..ed22ccd
--- /dev/null
+++ b/v17/leanback/res/values-en-rAU/strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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="orb_search_action" msgid="5651268540267663887">"Search Action"</string>
+ <string name="lb_search_bar_hint" msgid="8325490927970116252">"Search"</string>
+ <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
+ <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Play"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
+</resources>
diff --git a/v17/leanback/res/values-en-rGB/strings.xml b/v17/leanback/res/values-en-rGB/strings.xml
index 666fa5c..ed22ccd 100644
--- a/v17/leanback/res/values-en-rGB/strings.xml
+++ b/v17/leanback/res/values-en-rGB/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Play"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
</resources>
diff --git a/v17/leanback/res/values-en-rIN/strings.xml b/v17/leanback/res/values-en-rIN/strings.xml
index 666fa5c..ed22ccd 100644
--- a/v17/leanback/res/values-en-rIN/strings.xml
+++ b/v17/leanback/res/values-en-rIN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Speak to search"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Speak to search <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Play"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fast-Forward"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fast Forward %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rewind"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rewind %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Skip Next"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Skip Previous"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"More Actions"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselect Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Select Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselect Thumb Down"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Select Thumb Down"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Repeat None"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repeat All"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repeat One"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Enable Shuffle"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disable Shuffle"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Enable High Quality"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disable High Quality"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Enable Closed Captioning"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disable Closed Captioning"</string>
</resources>
diff --git a/v17/leanback/res/values-es-rUS/strings.xml b/v17/leanback/res/values-es-rUS/strings.xml
index 896535a..ab05f83 100644
--- a/v17/leanback/res/values-es-rUS/strings.xml
+++ b/v17/leanback/res/values-es-rUS/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Búsqueda"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Habla para buscar"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Habla para buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>."</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Habla para buscar en <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>."</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reproducir"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avanzar"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avanzar rápidamente %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retroceder"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobinar %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ir al siguiente"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ir al anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Más acciones"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desmarcar \"Me gusta\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Marcar \"Me gusta\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desmarcar \"No me gusta\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Marcar \"No me gusta\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"No repetir"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir todo"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uno"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Habilitar reproducción aleatoria"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Inhabilitar reproducción aleatoria"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Habilitar calidad alta"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar calidad alta"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
</resources>
diff --git a/v17/leanback/res/values-es/strings.xml b/v17/leanback/res/values-es/strings.xml
index 9990ae6..0cff1c9 100644
--- a/v17/leanback/res/values-es/strings.xml
+++ b/v17/leanback/res/values-es/strings.xml
@@ -19,7 +19,31 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="orb_search_action" msgid="5651268540267663887">"Buscar..."</string>
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Buscar"</string>
- <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Buscar por voz"</string>
+ <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Habla para buscar"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Buscar por voz <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Habla para buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reproducir"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rápido"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rápido %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rebobinar"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobinar %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Saltar siguiente"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Saltar anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Más acciones"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"No seleccionar pulgar hacia arriba"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Seleccionar pulgar hacia arriba"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"No seleccionar pulgar hacia abajo"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Seleccionar pulgar hacia abajo"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"No repetir"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir todo"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uno"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Habilitar reproducción aleatoria"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Inhabilitar reproducción aleatoria"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Habilitar alta calidad"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inhabilitar alta calidad"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Habilitar subtítulos"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inhabilitar subtítulos"</string>
</resources>
diff --git a/v17/leanback/res/values-et-rEE/strings.xml b/v17/leanback/res/values-et-rEE/strings.xml
index a097b5d..32fff96 100644
--- a/v17/leanback/res/values-et-rEE/strings.xml
+++ b/v17/leanback/res/values-et-rEE/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Öelge otsimiseks"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Otsige teenusest <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Kõnelge teenusest <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> otsimiseks"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Esita"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Peata"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Keri edasi"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Edasikerimine %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Keri tagasi"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Tagasikerimine %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Liigu järgmise üksuse juurde"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Liigu eelmise üksuse juurde"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Veel toiminguid"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Tühista hinnang Meeldib"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vali hinnang Meeldib"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Tühista hinnang Ei meeldi"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vali hinnang Ei meeldi"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ära korda midagi"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Korda kõike"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Korda ühte"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Luba juhuslikus järjekorras esitamine"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Keela juhuslikus järjekorras esitamine"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Luba kõrgkvaliteetne taasesitus"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Keela kõrgkvaliteetne taasesitus"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Luba subtiitrid"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Keela subtiitrid"</string>
</resources>
diff --git a/v17/leanback/res/values-eu-rES/strings.xml b/v17/leanback/res/values-eu-rES/strings.xml
index 2690a84..d9f9bf7 100644
--- a/v17/leanback/res/values-eu-rES/strings.xml
+++ b/v17/leanback/res/values-eu-rES/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Esan bilatu nahi duzuna"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Bilatu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Esan bilatu nahi duzuna, bilaketa hemen egiteko: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Erreproduzitu"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausatu"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Aurreratu"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Aurreratu %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Atzeratu"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Atzeratu %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Saltatu hurrengora"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Saltatu aurrekora"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Ekintza gehiago"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desautatu \"erpurua gora\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Hautatu \"erpurua gora\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desautatu \"erpurua behera\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Hautatu \"erpurua behera\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ez errepikatu"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Errepikatu guztiak"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Errepikatu bat"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Gaitu ausazko erreprodukzioa"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desgaitu ausazko erreprodukzioa"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Gaitu kalitate handiko erreprodukzioa"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desgaitu kalitate handiko erreprodukzioa"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Gaitu azpitituluak"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desgaitu azpitituluak"</string>
</resources>
diff --git a/v17/leanback/res/values-fa/strings.xml b/v17/leanback/res/values-fa/strings.xml
index fa4bb0c..bb615fc 100644
--- a/v17/leanback/res/values-fa/strings.xml
+++ b/v17/leanback/res/values-fa/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"برای جستجو صحبت کنید"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"جستجوی <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"جستجو با گفتن <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"پخش"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"توقف موقت"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"جلو بردن سریع"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"بازارسال سریع %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"عقب بردن"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"عقب بردن %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"رد شدن از بعدی"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"رد شدن از قبلی"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"عملکردهای بیشتر"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"لغو انتخاب رأی موافق"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"انتخاب رأی موافق"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"لغو انتخاب رأی مخالف"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"انتخاب رأی مخالف"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"تکرار هیچکدام"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"تکرار همه"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"یکبار تکرار"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"فعال کردن پخش تصادفی"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"غیرفعال کردن پخش تصادفی"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"فعال کردن کیفیت بالا"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"غیرفعال کردن کیفیت بالا"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"فعال کردن زیرنویس"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"غیرفعال کردن زیرنویس"</string>
</resources>
diff --git a/v17/leanback/res/values-fi/strings.xml b/v17/leanback/res/values-fi/strings.xml
index 3193006..9d38d3c 100644
--- a/v17/leanback/res/values-fi/strings.xml
+++ b/v17/leanback/res/values-fi/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tee haku puhumalla"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Haku: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Puhehaku: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Toista"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Keskeytä"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Kelaa eteenpäin"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Kelaa eteenpäin %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Kelaa taakse"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Kelaa taaksepäin %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Siirry seuraavaan"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Siirry edelliseen"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Lisää toimintoja"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Poista Tykkään-valinta"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Valitse Tykkään"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Poista En tykkää -valinta"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Valitse En tykkää"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ei uudelleentoistoa"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Toista kaikki uudelleen"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Toista yksi uudelleen"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ota satunnaistoisto käyttöön"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Poista satunnaistoisto käytöstä"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ota korkea laatu käyttöön"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Poista korkea laatu käytöstä"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ota tekstitys käyttöön"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Poista tekstitys käytöstä"</string>
</resources>
diff --git a/v17/leanback/res/values-fr-rCA/strings.xml b/v17/leanback/res/values-fr-rCA/strings.xml
index 20595c3..bbd3eea 100644
--- a/v17/leanback/res/values-fr-rCA/strings.xml
+++ b/v17/leanback/res/values-fr-rCA/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Énoncez votre recherche"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Rechercher dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Énoncez votre recherche dans <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Lecture"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rapide"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rapide à %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Reculer"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retour rapide à %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Passer à l\'élément suivant"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Passer à l\'élément précédent"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Autres actions"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Désélectionner la mention « J\'aime »"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Sélectionner la mention « J\'aime »"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Désélectionner la mention « Je n\'aime pas »"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Sélectionner la mention « Je n\'aime pas »"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Aucune répétition"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Tout lire en boucle"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Répéter un élément"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activer la lecture aléatoire"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Désactiver la lecture aléatoire"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activer la lecture haute qualité"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la lecture haute qualité"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer le sous-titrage"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver le sous-titrage"</string>
</resources>
diff --git a/v17/leanback/res/values-fr/strings.xml b/v17/leanback/res/values-fr/strings.xml
index 9a8d2c7..e9c051c 100644
--- a/v17/leanback/res/values-fr/strings.xml
+++ b/v17/leanback/res/values-fr/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Énoncer la recherche"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Rechercher \"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>\""</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Énoncer la recherche \"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>\""</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Lecture"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Interrompre"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rapide"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rapide de %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retour arrière"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retour arrière de %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ignorer l\'élément suivant"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ignorer l\'élément précédent"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Autres actions"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Désélectionner \"J\'aime\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Sélectionner \"J\'aime\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Désélectionner \"Je n\'aime pas\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Sélectionner \"Je n\'aime pas\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ne rien lire en boucle"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Tout lire en boucle"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Lire en boucle un élément"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Désactiver la lecture en mode aléatoire"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Désactiver la lecture en mode aléatoire"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activer la haute qualité"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Désactiver la haute qualité"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activer les sous-titres"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Désactiver les sous-titres"</string>
</resources>
diff --git a/v17/leanback/res/values-gl-rES/strings.xml b/v17/leanback/res/values-gl-rES/strings.xml
index b85dcd1..717b994 100644
--- a/v17/leanback/res/values-gl-rES/strings.xml
+++ b/v17/leanback/res/values-gl-rES/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fala para efectuar a busca"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fala para buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reproducir"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avance rápido"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avance rápido %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rebobinar"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Rebobinado %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Saltar seguinte"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Saltar anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Máis accións"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Anular \"Gústame\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Seleccionar polgar cara arriba"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Anular \"Non me gusta\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Seleccionar polgar cara abaixo"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Non repetir"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir todo"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir un"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activar reprodución aleatoria"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desactivar reprodución aleatoria"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activar alta calidade"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desactivar alta calidade"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activar subtítulos"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desactivar subtítulos"</string>
</resources>
diff --git a/v17/leanback/res/values-gu-rIN/strings.xml b/v17/leanback/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000..2e4f30f
--- /dev/null
+++ b/v17/leanback/res/values-gu-rIN/strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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="orb_search_action" msgid="5651268540267663887">"શોધ ક્રિયા"</string>
+ <string name="lb_search_bar_hint" msgid="8325490927970116252">"શોધો"</string>
+ <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"શોધવા માટે બોલો"</string>
+ <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> શોધો"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ને શોધવા માટે બોલો"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ચલાવો"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"થોભો"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ઝડપી ફોરવર્ડ"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"ફાસ્ટ ફોરવર્ડ કરો %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"રીવાઇન્ડ કરો"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX ને રિવાઇન્ડ કરો"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"આગલા પર જાઓ"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"પહેલાનાને છોડો"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"વધુ ક્રિયાઓ"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"એકદમ સરસ નાપસંદ કરો"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"એકદમ સરસ પસંદ કરો"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"સારું નથી નાપસંદ કરો"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"સારું નથી પસંદ કરો"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"કોઈનું પુનરાવર્તન નહીં"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"બધાનું પુનરાવર્તન કરો"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"એક પુનરાવર્તિત કરો"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"શફલ કરોને સક્ષમ કરો"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"શફલ કરોને અક્ષમ કરો"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ઉચ્ચ ગુણવત્તા સક્ષમ કરો"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ઉચ્ચ ગુણવત્તા અક્ષમ કરો"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ઉપશીર્ષક સક્ષમ કરો"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"વિગતવાર ઉપશીર્ષકોને અક્ષમ કરો"</string>
+</resources>
diff --git a/v17/leanback/res/values-hi/strings.xml b/v17/leanback/res/values-hi/strings.xml
index 0d3e72d..a926396 100644
--- a/v17/leanback/res/values-hi/strings.xml
+++ b/v17/leanback/res/values-hi/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"खोजने के लिए बोलें"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोजें"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोजने के लिए बोलें"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"चलाएं"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"रोकें"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"फ़ास्ट फ़ॉरवर्ड"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"फ़ास्ट फ़ॉरवर्ड %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"रिवाइंड करें"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"रिवाइंड %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"अगले पर जाएं"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"पिछले पर जाएं"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"अधिक विकल्प"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"पसंदीदा को ना चुनें"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"पसंदीदा चुनें"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"नापसंद को ना चुनें"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"नापसंद चुनें"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"कुछ भी न दोहराएं"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"सभी को दोहराएं"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"एक दोहराएं"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"फेर-बदल सक्षम करें"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"फेर-बदल अक्षम करें"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"उच्च गुणवत्ता सक्षम करें"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करें"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षक सक्षम करें"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षक अक्षम करें"</string>
</resources>
diff --git a/v17/leanback/res/values-hr/strings.xml b/v17/leanback/res/values-hr/strings.xml
index 89d8053..166369f 100644
--- a/v17/leanback/res/values-hr/strings.xml
+++ b/v17/leanback/res/values-hr/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Izgovorite upit za pretraživanje"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Tražite <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Izgovorite upit za pretraživanje <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reproduciraj"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauziraj"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Brzo naprijed"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Brzo unaprijed %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Unatrag"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Unatrag %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Preskoči na sljedeće"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Preskoči na prethodno"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Više radnji"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Poništi odabir palca gore"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Odaberi palac gore"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Poništi odabir palca dolje"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Odaberi palac dolje"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Bez ponavljanja"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ponovi sve"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ponovi jedno"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Omogući nasumičnu reprodukciju"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Onemogući nasumičnu reprodukciju"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Omogući visoku kvalitetu"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogući visoku kvalitetu"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogući titlove"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogući titlove"</string>
</resources>
diff --git a/v17/leanback/res/values-hu/strings.xml b/v17/leanback/res/values-hu/strings.xml
index e6eaacb..427f1cd 100644
--- a/v17/leanback/res/values-hu/strings.xml
+++ b/v17/leanback/res/values-hu/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Keresés"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Beszéljen a keresés indításához"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Keresés itt: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Mondjon valamit, hogy itt keressen: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Mondj valamit a kereséshez: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Lejátszás"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Szünet"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Gyors előretekerés"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Előretekerés %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Visszatekerés"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Visszatekerés %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ugrás a következőre"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ugrás az előzőre"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"További műveletek"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"„Tetszik” értékelés visszavonása"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"„Tetszik” értékelés kiválasztása"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"„Nem tetszik” értékelés visszavonása"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"„Nem tetszik” értékelés kiválasztása"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nincs ismétlés"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Összes ismétlése"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Egy ismétlése"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Véletlenszerű lejátszás engedélyezése"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Véletlenszerű lejátszás letiltása"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Jó minőségű lejátszás engedélyezése"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Jó minőségű lejátszás letiltása"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Feliratok engedélyezése"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Feliratok letiltása"</string>
</resources>
diff --git a/v17/leanback/res/values-hy-rAM/strings.xml b/v17/leanback/res/values-hy-rAM/strings.xml
index de8561f..7e8112e 100644
--- a/v17/leanback/res/values-hy-rAM/strings.xml
+++ b/v17/leanback/res/values-hy-rAM/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Խոսեք՝ որոնելու համար"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Որոնեք <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Խոսեք՝ <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> որոնելու համար"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Նվագարկել"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Դադարեցնել"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Արագ առաջ անցնել"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Առագ առաջանցում %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Հետ փաթաթել"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Հետանցում %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Անցնել հաջորդին"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Անցնել նախորդին"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Այլ գործողություններ"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ապանշել Հավանելու կոճակը"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Նշել Հավանելու կոճակը"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Ապանշել Չհավանելու կոճակը"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Նշել Չհավանելու կոճակը"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Չկրկնել"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Կրկնել բոլորը"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Կրկնել մեկը"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Միացնել խառը նվագարկումը"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Անջատել խառը նվագարկումը"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Միացնել բարձր որակը"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Անջատել բարձր որակը"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Միացնել խորագրերը"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Անջատել խորագրերը"</string>
</resources>
diff --git a/v17/leanback/res/values-in/strings.xml b/v17/leanback/res/values-in/strings.xml
index 9be0a01..2dca7d3 100644
--- a/v17/leanback/res/values-in/strings.xml
+++ b/v17/leanback/res/values-in/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Ucapkan untuk menelusuri"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Telusuri <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Ucapkan untuk menelusuri <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Putar"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Jeda"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Maju Cepat"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Maju %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Putar Ulang"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Mundur %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Lewati ke Berikutnya"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Lewati ke Sebelumnya"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Tindakan Lainnya"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Batal Pilih Yang Disukai"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Pilih Yang Disukai"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Batal Pilih Yang Tidak Disukai"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Pilih Yang Tidak Disukai"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Jangan Ulangi"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ulangi Semua"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ulangi Satu"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktifkan Acak"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Nonaktifkan Acak"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktifkan Kualitas Tinggi"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Nonaktifkan Kualitas Tinggi"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktifkan Pembuatan Teks"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Nonaktifkan Pembuatan Teks"</string>
</resources>
diff --git a/v17/leanback/res/values-is-rIS/strings.xml b/v17/leanback/res/values-is-rIS/strings.xml
index 29ccdc1..c84a4c6 100644
--- a/v17/leanback/res/values-is-rIS/strings.xml
+++ b/v17/leanback/res/values-is-rIS/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Talaðu til að leita"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Leita í <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Talaðu til að leita í <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Spila"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Hlé"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Spóla áfram"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spóla áfram %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spóla til baka"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spóla til baka %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Fara í næsta"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Fara í fyrra"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Fleiri aðgerðir"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Hætta við þumal upp"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Gefa þumal upp"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Hætta við þumal niður"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Gefa þumal niður"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Endurtaka ekkert"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Endurtaka allt"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Endurtaka eitt"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Kveikja á stokkun"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Slökkva á stokkun"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Kveikja á miklum gæðum"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Slökkva á miklum gæðum"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Kveikja á skjátextum"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Slökkva á skjátextum"</string>
</resources>
diff --git a/v17/leanback/res/values-it/strings.xml b/v17/leanback/res/values-it/strings.xml
index fa11e9d..1b58e0c 100644
--- a/v17/leanback/res/values-it/strings.xml
+++ b/v17/leanback/res/values-it/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Parla per cercare"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Cerca in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Parla per cercare in <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Riproduci"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Metti in pausa"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avanza velocemente"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avanti veloce: %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Riavvolgi"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Indietro: %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Salta successivo"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Salta precedente"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Altre azioni"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deseleziona Mi piace"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Seleziona Mi piace"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deseleziona pollice abbassato"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Seleziona pollice abbassato"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Non ripetere nessuno"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ripeti tutti"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ripeti uno"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Attiva riproduzione casuale"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Disattiva riproduzione casuale"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Attiva alta qualità"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Disattiva alta qualità"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Attiva sottotitoli"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Disattiva sottotitoli"</string>
</resources>
diff --git a/v17/leanback/res/values-iw/strings.xml b/v17/leanback/res/values-iw/strings.xml
index dacb052..f102498 100644
--- a/v17/leanback/res/values-iw/strings.xml
+++ b/v17/leanback/res/values-iw/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"דבר כדי לחפש"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"חפש את <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"דבר כדי לחפש את <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"הפעל"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"השהה"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"הרץ קדימה"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"העברה קדימה של %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"הרץ אחורה"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"העברה לאחור של %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"דלג אל הפריט הבא"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"דלג אל הפריט הקודם"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"עוד פעולות"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"בטל בחירה באגודל כלפי מעלה"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"בחר באגודל כלפי מעלה"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"בטל בחירה באגודל כלפי מטה"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"בחר באגודל כלפי מטה"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"אל תחזור על כלום"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"חזור על הכל"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"חזור על פריט אחד"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"הפעל ערבוב"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"השבת ערבוב"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"הפעל איכות גבוהה"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"השבת איכות גבוהה"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"הפעל כתוביות"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"השבת כתוביות"</string>
</resources>
diff --git a/v17/leanback/res/values-ja/strings.xml b/v17/leanback/res/values-ja/strings.xml
index 62b08b5..802631c 100644
--- a/v17/leanback/res/values-ja/strings.xml
+++ b/v17/leanback/res/values-ja/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"音声検索"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>を検索"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>を音声検索"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"再生"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"一時停止"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"早送り"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"早送り%1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"巻き戻し"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"巻き戻し%1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"次の曲にスキップ"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"前の曲にスキップ"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"その他の操作"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"グッドの選択を解除"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"グッドを選択"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"イマイチの選択を解除"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"イマイチを選択"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"繰り返しなし"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"全曲を繰り返し"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"1曲を繰り返し"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"シャッフルを有効にする"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"シャッフルを無効にする"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"高品質を有効にする"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"高品質を無効にする"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"字幕を有効にする"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"字幕を無効にする"</string>
</resources>
diff --git a/v17/leanback/res/values-ka-rGE/strings.xml b/v17/leanback/res/values-ka-rGE/strings.xml
index ab9492c..70aeada 100644
--- a/v17/leanback/res/values-ka-rGE/strings.xml
+++ b/v17/leanback/res/values-ka-rGE/strings.xml
@@ -22,4 +22,32 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"თქვით საძიებო ფრაზა"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>-ის ძიება"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"თქვით <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>-ის საძიებლად"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"დაკვრა"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"პაუზა"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"წინ გადახვევა"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for lb_playback_controls_fast_forward_multiplier (1058753672110224526) -->
+ <skip />
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"უკან გადახვევა"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for lb_playback_controls_rewind_multiplier (1640629531440849942) -->
+ <skip />
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"შემდეგის გამოტოვება"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"წინას გამოტოვება"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"დამატებითი ქმედებები"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"მაღალი შეფასების არჩევის გაუქმება"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"მაღალი შეფასების არჩევა"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"დაბალი შეფასების არჩევის გაუქმება"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"დაბალი შეფასების არჩევა"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"არცერთის გამეორება"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ყველას გამეორება"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ერთის გამეორება"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"არეულად დაკვრის ჩართვა"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"არეულად დაკვრის გამორთვა"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"მაღალი ხარისხის ჩართვა"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"მაღალი ხარისხის გამორთვა"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"დახურული წარწერების ჩართვა"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"დახურული წარწერების გაუქმება"</string>
</resources>
diff --git a/v17/leanback/res/values-kk-rKZ/strings.xml b/v17/leanback/res/values-kk-rKZ/strings.xml
index 160a8e7..9ed6ce2 100644
--- a/v17/leanback/res/values-kk-rKZ/strings.xml
+++ b/v17/leanback/res/values-kk-rKZ/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Іздеу үшін сөйлеу"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> іздеу"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> іздеу үшін сөйлеңіз"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Ойнату"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Кідірту"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Алға айналдыру"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX алға айналдыру"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Кері айналдыру"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX кері айналдыру"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Келесіге өту"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Алдыңғыға өту"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Қосымша әрекеттер"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Саусақты жоғары қаратудан таңдауды алу"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Саусақты жоғары қаратуды таңдау"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Саусақты төмен қаратудан таңдауды алу"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Саусақты төмен қаратуды таңдау"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ешқайсысын қайталамау"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Барлығын қайталау"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Біреуін қайталау"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Кездейсоқ ойнатуды қосу"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Кездейсоқ ойнатуды өшіру"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Жоғары сапаны қосу"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Жоғары сапаны өшіру"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жасырын титрлерді қосу"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жасырын титрлерді өшіру"</string>
</resources>
diff --git a/v17/leanback/res/values-km-rKH/strings.xml b/v17/leanback/res/values-km-rKH/strings.xml
index 92245b7..7874af2 100644
--- a/v17/leanback/res/values-km-rKH/strings.xml
+++ b/v17/leanback/res/values-km-rKH/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"និយាយដើម្បីស្វែងរក"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"ស្វែងរក <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"និយាយដើម្បីស្វែងរក <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ចាក់"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ផ្អាក"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"បញ្ជូនបន្តរហ័ស"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"ខាទៅមុខ %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ខាថយក្រោយ"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"ខាថយក្រោយ %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"រំលងបន្ទាប់"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"រំលងមុន"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"សកម្មភាពច្រើនទៀត"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"មិនជ្រើសមេដៃឡើងវិញ"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"ជ្រើសមេដៃឡើងលើ"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"មិនជ្រើសមេដៃចុះក្រោម"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"ជ្រើសមេដៃចុះក្រោម"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"មិនធ្វើឡើងវិញ"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ធ្វើម្ដងទៀតទាំងអស់"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ធ្វើឡើងវិញម្ដង"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"បើកការច្របល់"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"បិទការច្របល់"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"បើកគុណភាពខ្ពស់"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"បិទគុណភាពខ្ពស់"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"បើកការដាក់ចំណងដែលបានបិទ"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"បិទការដាក់ចំណងដែលបានបិទ"</string>
</resources>
diff --git a/v17/leanback/res/values-kn-rIN/strings.xml b/v17/leanback/res/values-kn-rIN/strings.xml
index 6ca527f..196b154 100644
--- a/v17/leanback/res/values-kn-rIN/strings.xml
+++ b/v17/leanback/res/values-kn-rIN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ಹುಡುಕಲು ಮಾತನಾಡಿ"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಹುಡುಕಿ"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಮಾತನಾಡಿ ಹುಡುಕಾಟ ನಡೆಸಿ"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ಪ್ಲೇ ಮಾಡು"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ವಿರಾಮಗೊಳಿಸು"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ಫಾಸ್ಟ್ ಫಾರ್ವರ್ಡ್"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"ಫಾಸ್ಟ್ ಫಾರ್ವರ್ಡ್ %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ರೀವೈಂಡ್"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"ರಿವೈಂಡ್ %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ಮುಂದೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ಹಿಂದೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"ಹೆಚ್ಚು ಕ್ರಿಯೆಗಳು"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"ಥಂಬ್ ಅಪ್ ಆಯ್ಕೆರದ್ದುಮಾಡಿ"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"ಥಂಬ್ ಅಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"ಥಂಬ್ ಡೌನ್ ಆಯ್ಕೆರದ್ದುಮಾಡಿ"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"ಥಂಬ್ ಡೌನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ಯಾವುದನ್ನೂ ಪುನರಾವರ್ತಿಸಬೇಡಿ"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ಎಲ್ಲವನ್ನು ಪುನರಾವರ್ತಿಸಿ"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ಒಂದನ್ನು ಪುನರಾವರ್ತಿಸಿ"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ಜೋಡಿಸುವುದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ಜೋಡಿಸುವುದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ಹೆಚ್ಚು ಗುಣಮಟ್ಟವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ಹೆಚ್ಚು ಗುಣಮಟ್ಟವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
</resources>
diff --git a/v17/leanback/res/values-ko/strings.xml b/v17/leanback/res/values-ko/strings.xml
index af0130d..c244dbf 100644
--- a/v17/leanback/res/values-ko/strings.xml
+++ b/v17/leanback/res/values-ko/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"음성 검색"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> 검색"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> 음성 검색"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d배속"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d배속"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"재생"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"일시중지"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"빨리 감기"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$d배속 빨리 감기"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"되감기"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$d배속 되감기"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"다음으로 건너뛰기"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"이전으로 건너뛰기"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"추가 작업"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"추천 선택 해제"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"추천 선택"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"비추천 선택 해제"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"비추천 선택"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"반복 안함"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"전체 반복"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"한 항목 반복"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"셔플 사용 설정"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"셔플 사용 중지"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"고화질 사용 설정"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"고화질 사용 중지"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"자막 사용 설정"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"자막 사용 중지"</string>
</resources>
diff --git a/v17/leanback/res/values-ky-rKG/strings.xml b/v17/leanback/res/values-ky-rKG/strings.xml
index 64a2e72..4ddb284 100644
--- a/v17/leanback/res/values-ky-rKG/strings.xml
+++ b/v17/leanback/res/values-ky-rKG/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Издөө үчүн сүйлөңүз"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> издөө"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> издөө үчүн сүйлөңүз"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Ойнотуу"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Тындыруу"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Алдыга түрүү"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Алдыга түрүү %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Артка түрүү"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Артка түрүү %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Кийинкини өткөрүп жиберүү"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Мурункуну өткөрүп жиберүү"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Дагы көнүгүүлөр"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Жактырууну тандоодон чыгаруу"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Жактырууну тандоо"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Жактырбоону тандоодон чыгаруу"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Жактырбоону тандоо"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Эч бирин кайталабоо"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Баарын кайталоо"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Бирөөнү кайталоо"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Аралаштырууну иштетүү"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Аралаштырууну өчүрүү"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Жогорку сапатты иштетүү"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Жогорку сапатты өчүрүү"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Жабык субтитрлерди иштетүү"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Жабык субтитрлерди өчүрүү"</string>
</resources>
diff --git a/v17/leanback/res/values-lo-rLA/strings.xml b/v17/leanback/res/values-lo-rLA/strings.xml
index 107f989..35f519b 100644
--- a/v17/leanback/res/values-lo-rLA/strings.xml
+++ b/v17/leanback/res/values-lo-rLA/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ເວົ້າເພື່ອຊອກຫາ"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"ຊອກຫາ <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"ເວົ້າເພື່ອຊອກຫາ <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ຫຼິ້ນ"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ຢຸດຊົ່ວຄາວ"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ເລື່ອນໄປໜ້າ"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"ໄປໜ້າແບບໄວ %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ຣີວາຍກັບ"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"ກັບຄືນ %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ຂ້າມໄປຕໍ່"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ຂ້າມໄປກ່ອນໜ້າ"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"ຄຳສັ່ງເພີ່ມເຕີມ"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"ຢຸດເລືອກຍົກໂປ້ແລ້ວ"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"ເລືອກຍົກໂປ້ແລ້ວ"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"ຢຸດຊີ້ໂປ້ລົງແລ້ວ"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"ເລືອກຊີ້ໂປ້ລົງແລ້ວ"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ບໍ່ຫຼິ້ນຊ້ຳ"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ຫຼິ້ນຊ້ຳທັງໝົດ"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ຫຼິ້ນຊ້ຳ"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ເປີດນຳໃຊ້ການສະຫຼັບ"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ປິດນຳໃຊ້ການສະຫຼັບ"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ເປີດນຳໃຊ້ການຫຼິ້ນດ້ວຍຄຸນນະພາບສູງ"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ປິດນຳໃຊ້ການຫຼິ້ນດ້ວຍຄຸນນະພາບສູງ"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ເປີດນຳໃຊ້ຄຳບັນຍາຍແບບປິດ"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ປິດນຳໃຊ້ຄຳບັນຍາຍແບບປິດ"</string>
</resources>
diff --git a/v17/leanback/res/values-lt/strings.xml b/v17/leanback/res/values-lt/strings.xml
index f765d04..6ca2bab 100644
--- a/v17/leanback/res/values-lt/strings.xml
+++ b/v17/leanback/res/values-lt/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Pasakykite, kad ieškotumėte"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Ieškoti „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Kalbėkite, kad ieškotumėte „<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>“"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d k."</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d k."</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Leisti"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pristabdyti"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Sukti pirmyn"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Sukti pirmyn %1$d k. greičiau"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Sukti atgal"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Sukti atgal %1$d k. greičiau"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Praleisti kitą"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Praleisti ankstesnį"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Daugiau veiksmų"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Panaikinti parinkties „Patinka“ pasirinkimą"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Pasirinkti parinktį „Patinka“"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Panaikinti parinkties „Nepatinka“ pasirinkimą"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Pasirinkti parinktį „Nepatinka“"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nekartoti nieko"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Kartoti viską"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Kartoti vieną"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Įgalinti maišymą"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Išjungti maišymą"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Įgalinti aukštą kokybę"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Išjungti aukštą kokybę"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Įgalinti subtitrus"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Išjungti subtitrus"</string>
</resources>
diff --git a/v17/leanback/res/values-lv/strings.xml b/v17/leanback/res/values-lv/strings.xml
index 677ae6b..7d3bc2b 100644
--- a/v17/leanback/res/values-lv/strings.xml
+++ b/v17/leanback/res/values-lv/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Meklēt"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Runāt, lai meklētu"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Meklējiet <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Runājiet, lai meklētu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Runājiet, lai meklētu: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Atskaņot"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauzēt"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Pārtīt uz priekšu"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Pārtīt uz priekšu %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Attīt atpakaļ"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Attīt atpakaļ %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Izlaist nākamo"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Izlaist iepriekšējo"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Citas darbības"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Atcelt “Patīk” atlasi"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Atlasīt “Patīk”"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Atcelt “Nepatīk” atlasi"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Atlasīt “Nepatīk”"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Neatkārtot nevienu"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Atkārtot visu"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Atkārtot vienu"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Iespējot atskaņošanu jauktā secībā"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Atspējot atskaņošanu jauktā secībā"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Iespējot augstas kvalitātes vienumu atskaņošanu"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Atspējot augstas kvalitātes vienumu atskaņošanu"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Iespējot slēgtos parakstus"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Atspējot slēgtos parakstus"</string>
</resources>
diff --git a/v17/leanback/res/values-mk-rMK/strings.xml b/v17/leanback/res/values-mk-rMK/strings.xml
index 8ab8384..75666e0 100644
--- a/v17/leanback/res/values-mk-rMK/strings.xml
+++ b/v17/leanback/res/values-mk-rMK/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Зборувајте за да пребарувате"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Пребарувај <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Кажете за да се пребарува <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Пушти"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Пауза"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Брзо премотај напред"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Премотај напред %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Премотај назад"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Премотај назад %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Прескокни на следна"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Прескокни на претходна"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Повеќе дејства"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Откажи палец нагоре"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Избери палец нагоре"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Откажи палец надолу"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Избери палец надолу"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Не повторувај ниту една"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Повтори ги сите"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Повтори една"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Овозможи мешање"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Оневозможи мешање"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Овозможи висок квалитет"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Оневозможи висок квалитет"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Овозможи затворено објаснување"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Оневозможи затворено објаснување"</string>
</resources>
diff --git a/v17/leanback/res/values-ml-rIN/strings.xml b/v17/leanback/res/values-ml-rIN/strings.xml
index e31770d..b900f09 100644
--- a/v17/leanback/res/values-ml-rIN/strings.xml
+++ b/v17/leanback/res/values-ml-rIN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ശബ്ദം ഉപയോഗിച്ച് തിരയുക"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുക"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുന്നതിന് സംസാരിക്കുക"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"പ്ലേ ചെയ്യുക"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"താൽക്കാലികമായി നിർത്തുക"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ഫാസ്റ്റ് ഫോർവേഡ് ചെയ്യുക"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX വേഗത്തിൽ ഫോർവേഡുചെയ്യുക"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"റിവൈൻഡുചെയ്യുക"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX റിവൈൻഡുചെയ്യുക"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"അടുത്തതിലേക്ക് പോകുക"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"മുമ്പത്തേതിലേക്ക് പോകുക"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"കൂടുതൽ പ്രവർത്തനങ്ങൾ"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"തമ്പ് അപ്പ് തിരഞ്ഞെടുത്തത് മാറ്റുക"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"തമ്പ് അപ്പ് തിരഞ്ഞെടുക്കുക"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"തമ്പ് ഡൗൺ തിരഞ്ഞെടുത്തത് മാറ്റുക"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"തമ്പ് ഡൗൺ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ഒന്നും ആവർത്തിക്കരുത്"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"എല്ലാം ആവർത്തിക്കുക"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ഒന്ന് ആവർത്തിക്കുക"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ഷഫിൾ ചെയ്യുന്നത് പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ഷഫിൾ ചെയ്യുന്നത് പ്രവർത്തനരഹിതമാക്കുക"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ഉയർന്ന നിലവാരം പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ഉയർന്ന നിലവാരം പ്രവർത്തനരഹിതമാക്കുക"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"അടച്ച അടിക്കുറിപ്പ് നൽകൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
</resources>
diff --git a/v17/leanback/res/values-mn-rMN/strings.xml b/v17/leanback/res/values-mn-rMN/strings.xml
index a58dfe9..e4a8fcd 100644
--- a/v17/leanback/res/values-mn-rMN/strings.xml
+++ b/v17/leanback/res/values-mn-rMN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Ярьж хайх"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> Хайх"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> хайхын тулд ярина уу"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Тоглуулах"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Түр зогсоох"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Хурдан урагшлуулах"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Түргэн Урагш Гүйлгэх %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Буцааж хураах"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Хойш Гүйлгэх %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Дараагийнхийг алгасах"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Өмнөхийг алгасах"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Өөр үйлдлүүд"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Дээш эрхий хурууг цуцлах"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Дээш эрхий хурууг сонгох"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Доош эрхий хурууг цуцлах"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Доош эрхий хурууг сонгох"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Алийг нь ч давтахгүй"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Бүгдийг давтах"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Нэгийг давтах"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Холихыг идэвхжүүлэх"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Холихыг идэвхгүйжүүлэх"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Өндөр чанарыг идэвхжүүлэх"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Өндөр чанарыг идэвхгүйжүүлэх"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Текст тайлбарыг идэвхжүүлэх"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Текст тайлбарыг идэвхгүйжүүлэх"</string>
</resources>
diff --git a/v17/leanback/res/values-mr-rIN/strings.xml b/v17/leanback/res/values-mr-rIN/strings.xml
index 296b21c..11748ec 100644
--- a/v17/leanback/res/values-mr-rIN/strings.xml
+++ b/v17/leanback/res/values-mr-rIN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"शोधण्यासाठी बोला"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधा"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधण्यासाठी बोला"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"प्ले करा"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"विराम द्या"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"फास्ट फॉरवर्ड करा"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"फास्ट फॉरवर्ड %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"रिवाईँड करा"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"रीवाईंड %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"पुढील वगळा"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"मागील वगळा"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"अधिक क्रिया"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"वर अंगठा निवड रद्द करा"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"वर अंगठा निवडा"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"खाली अंगठा निवड रद्द करा"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"खाली अंगठा निवडा"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"काहीही पुनरावृत्ती करू नका"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"सर्व पुनरावृत्ती करा"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"एक पुनरावृत्ती करा"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"शफल करा सक्षम करा"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"शफल करा अक्षम करा"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"उच्च गुणवत्ता सक्षम करा"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करा"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षके सक्षम करा"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"उपशीर्षके अक्षम करा"</string>
</resources>
diff --git a/v17/leanback/res/values-ms-rMY/strings.xml b/v17/leanback/res/values-ms-rMY/strings.xml
index d915409..c073e43 100644
--- a/v17/leanback/res/values-ms-rMY/strings.xml
+++ b/v17/leanback/res/values-ms-rMY/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tutur untuk membuat carian"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Cari <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Sebut untuk mencari <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Main"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Jeda"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Mara Laju"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Lajukan %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Gulung semula"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Gulung semula %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Langkau Seterusnya"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Langkau Sebelumnya"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Lagi Tindakan"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Nyahpilih Bagus"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Pilih Bagus"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Nyahpilih Tidak Bagus"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Pilih Tidak Bagus"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Jangan Ulang"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ulang Semua"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ulang Satu"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Dayakan Rombak"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Lumpuhkan Rombak"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Dayakan Kualiti Tinggi"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Lumpuhkan Kualiti Tinggi"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Dayakan Kapsyen Tertutup"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Lumpuhkan Kapsyen Tertutup"</string>
</resources>
diff --git a/v17/leanback/res/values-my-rMM/strings.xml b/v17/leanback/res/values-my-rMM/strings.xml
index 76e70f2..2efaf7f 100644
--- a/v17/leanback/res/values-my-rMM/strings.xml
+++ b/v17/leanback/res/values-my-rMM/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ရှာဖွေရန် ပြောပါ"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ကို ရှာရန်"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ကို ရှာရန် ပြောပါ"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ဖွင့်ရန်"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ခဏရပ်ရန်"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ရှေ့သို့ သွားရန်"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"ရှေ့သို့ ရစ်ရန် %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ပြန်ရစ်ရန်"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"နောက်သို့ ရစ်ရန် %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"နောက်တစ်ပုဒ်သို့ ကျော်ရန်"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ယခင်တစ်ပုဒ်သို့ သွားရန်"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"နောက်ထပ် လုပ်ဆောင်ချက်များ"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"နှစ်ခြိုက်သော သင်္ကေတအား မရွေးရန်"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"နှစ်ခြိုက်သော သင်္ကေတအား ရွေးရန်"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"မနှစ်ခြိုက်သော သင်္ကေတအား မရွေးရန်"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"မနှစ်ခြိုက်သော သင်္ကေတအား ရွေးရန်"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ထပ်တလဲလဲမဖွင့်ရန်"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"အားလုံး ထပ်တလဲလဲဖွင့်ရန်"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"တစ်ခုအား ထပ်တလဲလဲဖွင့်ရန်"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ရောသမမွှေခြင်း ပြုရန်"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ရောသမမေွှခြင်း မပြုရန်"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"အရည်အသွေးကောင်းအား ဖွင့်ရန်"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"အရည်အသွေးကောင်းအား ပိတ်ထားရန်"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"စာတမ်းထိုး ဖွင့်ရန်"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"စာတမ်းထိုးအား ပိတ်ထားရန်"</string>
</resources>
diff --git a/v17/leanback/res/values-nb/strings.xml b/v17/leanback/res/values-nb/strings.xml
index c1fe682..f5ab2e1 100644
--- a/v17/leanback/res/values-nb/strings.xml
+++ b/v17/leanback/res/values-nb/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Snakk for å søke"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Søk i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Snakk for å søke i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Spill av"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Sett på pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Fremoverspoling"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Fremoverspoling %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Tilbakespoling"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Tilbakespoling %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Hopp til neste"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Hopp til forrige"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Flere handlinger"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Fjern valg av tommel opp"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Velg tommel opp"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Fjern valg av tommel ned"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Velg tommel ned"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ikke gjenta noen"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Gjenta alle"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Gjenta én"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktivér avspilling i tilfeldig rekkefølge"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Deaktiver avspilling i tilfeldig rekkefølge"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivér høy kvalitet"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Deaktiver høy kvalitet"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivér teksting"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Deaktiver teksting"</string>
</resources>
diff --git a/v17/leanback/res/values-ne-rNP/strings.xml b/v17/leanback/res/values-ne-rNP/strings.xml
index 81ce461..c399985 100644
--- a/v17/leanback/res/values-ne-rNP/strings.xml
+++ b/v17/leanback/res/values-ne-rNP/strings.xml
@@ -22,4 +22,30 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"खोजी गर्न बोल्नुहोस्"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोज्नुहोस्"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> खोजी गर्न बोल्नुहोस्"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"प्ले गर्नुहोस्"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"रोक्नुहोस्"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"फास्ट फर्वार्ड"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for lb_playback_controls_fast_forward_multiplier (1058753672110224526) -->
+ <skip />
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"दोहोर्याउनुहोस्"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"पुन: वाइन्ड गर्नुहोस् %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"अर्को छोड्नुहोस्"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"अघिल्लो छोड्नुहोस्"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"थप कार्यहरू"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"औंठा माथि चयन नगर्नुहोस्"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"औंठा माथि चयन गर्नुहोस्"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"औंठा तल चयन नगर्नुहोस्"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"औंठा तल चयन गर्नुहोस्"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"कुनै पनि नदोहोर्याउनुहोस्"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"सबै दोहोर्याउनुहोस्"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"एउटा दोहोर्याउनुहोस्"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"सफ्फल सक्षम"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"सफ्फल असक्षम"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"उच्च गुणस्तर सक्षम"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणस्तर असक्षम"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"बन्द क्याप्सनहरु सक्षम"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"बन्द क्याप्सनहरु असक्षम"</string>
</resources>
diff --git a/v17/leanback/res/values-nl/strings.xml b/v17/leanback/res/values-nl/strings.xml
index 5c0ba2e..fe73141 100644
--- a/v17/leanback/res/values-nl/strings.xml
+++ b/v17/leanback/res/values-nl/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Spreek om te zoeken"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> zoeken"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Spreek om <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> te zoeken"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Afspelen"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Onderbreken"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Vooruitspoelen"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Vooruitspoelen %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Terugspoelen"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Terugspoelen %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Naar volgende"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Naar vorige"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Meer acties"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Selectie van \'Leuk\' ongedaan maken"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"\'Leuk\' selecteren"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Selectie van \'Niet leuk\' ongedaan maken"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"\'Niet leuk\' selecteren"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Niet herhalen"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Alles herhalen"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Eén herhalen"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Shuffle inschakelen"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Shuffle uitschakelen"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Hoge kwaliteit inschakelen"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Hoge kwaliteit uitschakelen"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ondertiteling inschakelen"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Ondertiteling uitschakelen"</string>
</resources>
diff --git a/v17/leanback/res/values-pa-rIN/strings.xml b/v17/leanback/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000..f9c7c4b
--- /dev/null
+++ b/v17/leanback/res/values-pa-rIN/strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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="orb_search_action" msgid="5651268540267663887">"ਖੋਜ ਕਿਰਿਆ"</string>
+ <string name="lb_search_bar_hint" msgid="8325490927970116252">"ਖੋਜੋ"</string>
+ <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"ਖੋਜਣ ਲਈ ਬੋਲੋ"</string>
+ <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ਖੋਜੋ"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ਖੋਜਣ ਲਈ ਬੋਲੋ"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ਪਲੇ ਕਰੋ"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"ਰੋਕੋ"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"ਅੱਗੇ ਭੇਜੋ"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX ਨੂੰ ਅੱਗੇ ਭੇਜੋ"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ਰੀਵਾਈਂਡ"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX ਨੂੰ ਰੀਵਾਈਂਡ ਕਰੋ"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ਅਗਲਾ ਨੂੰ ਛੱਡੋ"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ਪਿਛਲਾ ਨੂੰ ਛੱਡੋ"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"ਹੋਰ ਕਿਰਿਆਵਾਂ"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"ਥੰਬ ਅਪ ਨੂੰ ਅਚੋਣਵਾਂ ਕਰੋ"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"ਥੰਬ ਅਪ ਨੂੰ ਚੁਣੋ"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"ਥੰਬ ਡਾਊਨ ਨੂੰ ਅਚੋਣਵਾਂ ਕਰੋ"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"ਥੰਬ ਡਾਊਨ ਨੂੰ ਚੁਣੋ"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ਕੋਈ ਵੀ ਨਾ ਦੁਹਰਾਓ"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"ਸਾਰਿਆਂ ਨੂੰ ਦੁਹਰਾਓ"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ਇੱਕ ਦੁਹਰਾਓ"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ਸ਼ਫਲ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ਸ਼ਫਲ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ਉੱਚ ਗੁਣਵੱਤਾ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਸਮਰੱਥ ਬਣਾਓ"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ਬੰਦ ਕੈਪਸ਼ਨਿੰਗ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
+</resources>
diff --git a/v17/leanback/res/values-pl/strings.xml b/v17/leanback/res/values-pl/strings.xml
index 9942bc7..f6280a3 100644
--- a/v17/leanback/res/values-pl/strings.xml
+++ b/v17/leanback/res/values-pl/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Szukaj"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Powiedz, aby wyszukać"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Szukaj <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Powiedz, by wyszukać <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Powiedz, by wyszukać w aplikacji <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Odtwórz"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Wstrzymaj"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Przewiń do przodu"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Przewiń do przodu %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Przewiń do tyłu"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Przewiń do tyłu %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Pomiń następny"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Pomiń poprzedni"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Więcej czynności"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Odznacz Lubię"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Zaznacz Lubię"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Odznacz Nie lubię"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Zaznacz Nie lubię"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nie powtarzaj"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Powtórz wszystkie"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Powtórz jeden"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Włącz odtwarzanie losowe"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Wyłącz odtwarzanie losowe"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Włącz wysoką jakość"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Wyłącz wysoką jakość"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Włącz napisy"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Wyłącz napisy"</string>
</resources>
diff --git a/v17/leanback/res/values-pt-rPT/strings.xml b/v17/leanback/res/values-pt-rPT/strings.xml
index 0f15262..f3bf4aa 100644
--- a/v17/leanback/res/values-pt-rPT/strings.xml
+++ b/v17/leanback/res/values-pt-rPT/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fale para pesquisar"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fale para pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reproduzir"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Interromper"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avançar"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avançar %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Recuar"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Recuar %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Avançar para o seguinte"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Avançar para o anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mais ações"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desselecionar Gosto"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Selecionar Gosto"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desselecionar Não gosto"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Selecionar Não gosto"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Não repetir"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir tudo"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir um"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ativar reprodução aleatória"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desativar reprodução aleatória"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ativar alta qualidade"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar legendas"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar legendas"</string>
</resources>
diff --git a/v17/leanback/res/values-pt/strings.xml b/v17/leanback/res/values-pt/strings.xml
index 0f15262..13d01a5 100644
--- a/v17/leanback/res/values-pt/strings.xml
+++ b/v17/leanback/res/values-pt/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fale para pesquisar"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fale para pesquisar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Reproduzir"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausar"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Avançar"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Avançar %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Retroceder"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Retroceder %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Pular próxima"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Pular anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mais ações"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Desmarcar gostei"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Marcar gostei"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Desmarcar não gostei"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Marcar não gostei"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Não repetir"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetir tudo"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetir uma"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Ativar reprodução aleatória"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Desativar reprodução aleatória"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Ativar alta qualidade"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Desativar alta qualidade"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Ativar closed captioning"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Desativar closed captioning"</string>
</resources>
diff --git a/v17/leanback/res/values-ro/strings.xml b/v17/leanback/res/values-ro/strings.xml
index fd354372..cb6aa4a 100644
--- a/v17/leanback/res/values-ro/strings.xml
+++ b/v17/leanback/res/values-ro/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Căutați"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Rostiți pentru a căuta"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Căutați <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vorbiți pentru a căuta <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vorbiți pentru a căuta în <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Redă"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Întrerupe"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Derulează rapid înainte"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Derulați rapid înainte cu %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Derulează"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Derulați înapoi cu %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ignoră articolul următor"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ignoră articolul anterior"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Mai multe acţiuni"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Deselectează „Îmi place”"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Selectează „Îmi place”"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Deselectează „Nu-mi place”"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Selectează „Nu-mi place”"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Nu repetă"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Repetă toate"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Repetă unul"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Activează redarea în mod aleatoriu"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Dezactivează redarea în mod aleatoriu"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Activează calitatea înaltă"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Dezactivează calitatea înaltă"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Activează subtitrările"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Dezactivează subtitrările"</string>
</resources>
diff --git a/v17/leanback/res/values-ru/strings.xml b/v17/leanback/res/values-ru/strings.xml
index a06ebbc..fb03f9d 100644
--- a/v17/leanback/res/values-ru/strings.xml
+++ b/v17/leanback/res/values-ru/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Поиск"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Произнесите запрос"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Поиск здесь: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Произнесите запрос для поиска здесь: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Произнесите запрос, чтобы найти <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Воспроизвести."</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Приостановить."</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Перемотка вперед."</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Перемотка вперед %1$dX."</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Перемотать назад."</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Перемотка назад %1$dX."</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Перейти к следующему элементу."</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Перейти к предыдущему элементу."</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Другие действия."</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Убрать отметку Нравится."</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Поставить отметку Нравится."</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Убрать отметку Не нравится."</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Поставить отметку Не нравится."</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Не повторять."</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Повторять все."</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Повторять один элемент."</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Включить перемешивание."</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Отключить перемешивание."</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Включить высокое качество."</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Отключить высокое качество."</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Включить субтитры."</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Отключить субтитры."</string>
</resources>
diff --git a/v17/leanback/res/values-si-rLK/strings.xml b/v17/leanback/res/values-si-rLK/strings.xml
index 77742b5..e5c0cf4 100644
--- a/v17/leanback/res/values-si-rLK/strings.xml
+++ b/v17/leanback/res/values-si-rLK/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"සෙවීමට කථා කරන්න"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> සොයන්න"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> සොයන්න කථා කරන්න"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ධාවනය කරන්න"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"විරාමය"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"වේගයෙන් ඉදිරියට යන"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX වේගයෙන් ඉදිරියට යවන්න"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"නැවත ඔතන්න"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX ආපස්සට යවන්න"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ඊළඟ එක මග අරින්න"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"කළින් එක මග අරින්න"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"තව ක්රියාකාරකම්"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"මහපටැඟිල්ල ඉහළට තිබීම තේරීම නොකරන්න"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"මහපටැඟිල්ල ඉහළට තිබීම තේරීම කරන්න"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"මහපටැඟිල්ල පහළට තිබීම තේරීම නොකරන්න"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"මහපටැඟිල්ල පහළට තිබීම තේරීම කරන්න"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"නැවත කරන්න කිසිවක් නැත"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"සියල්ල නැවත කරන්න"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"එකක් නැවත කරන්න"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"ඇනීම සබල කරන්න"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ඇනීම අබල කරන්න"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"උපරිම ගුණත්වය සබල කරන ලදි"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"උපරිම ගුණත්වය අබල කරන ලදි"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"වැසුණු ශිර්ෂ කිරීම සබල කරන ලදි"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"වැසුණු ශිර්ෂ කිරීම අබල කරන ලදි"</string>
</resources>
diff --git a/v17/leanback/res/values-sk/strings.xml b/v17/leanback/res/values-sk/strings.xml
index 8af51d8..74a9044 100644
--- a/v17/leanback/res/values-sk/strings.xml
+++ b/v17/leanback/res/values-sk/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Hľadať"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Hovorením spustíte vyhľadávanie"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Vyhľadať výraz <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Vyslovením výrazu <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> spustíte jeho vyhľad."</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Hovorte na vyhľadávanie v kontexte <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Prehrať"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pozastaviť"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Pretočiť dopredu"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Pretočiť dopredu %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Pretočiť späť"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Pretočiť späť %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Prejsť na ďalšiu položku"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Prejsť na predchádzajúcu položku"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Viac akcií"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Zrušiť Páči sa mi"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Vybrať Páči sa mi"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Zrušiť Nepáči sa mi"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Vybrať Nepáči sa mi"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Neopakovať"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Opakovať všetko"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Opakovať jednu položku"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Zapnúť náhodné prehrávanie"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Vypnúť náhodné prehrávanie"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Povoliť médiá vo vysokej kvalite"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zakázať médiá vo vysokej kvalite"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Zapnúť skryté titulky"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Vypnúť skryté titulky"</string>
</resources>
diff --git a/v17/leanback/res/values-sl/strings.xml b/v17/leanback/res/values-sl/strings.xml
index d367572..1af639b 100644
--- a/v17/leanback/res/values-sl/strings.xml
+++ b/v17/leanback/res/values-sl/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Izgovorite, če želite iskati"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Iskanje: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Govorite, če želite iskati: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d-kratno"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d-kratno"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Predvajaj"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Zaustavi"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Previj naprej"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Hitro previjanje naprej – %1$d-kratno"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Previj nazaj"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Previjanje nazaj – %1$d-kratno"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Preskoči naslednje"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Preskoči prejšnje"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Več dejanj"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Prekliči izbor palca gor"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Izberi palec gor"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Prekliči izbor palca dol"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Izberi palec dol"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ne ponovi"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ponovi vse"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ponovi eno"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Omogoči naključno predvajanje"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Onemogoči naključno predvajanje"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Omogoči visoko kakovost"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Onemogoči visoko kakovost"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Omogoči podnapise"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Onemogoči podnapise"</string>
</resources>
diff --git a/v17/leanback/res/values-sq-rAL/strings.xml b/v17/leanback/res/values-sq-rAL/strings.xml
new file mode 100644
index 0000000..28c313f
--- /dev/null
+++ b/v17/leanback/res/values-sq-rAL/strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT 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="orb_search_action" msgid="5651268540267663887">"Veprim i kërkimit"</string>
+ <string name="lb_search_bar_hint" msgid="8325490927970116252">"Kërko"</string>
+ <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Fol për të kërkuar"</string>
+ <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Kërko për <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Fol për të kërkuar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Luaj"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pauzë"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Përparo me shpejtësi"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Përparo me shpejtësi %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Kthe në fillim"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Kthe në fillim %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Kapërce për te tjetra"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Kapërce të mëparshmin"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Veprime të tjera"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Hiq nga përzgjedhja \"Gishti lart\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Përzgjidh \"Gishtin sipër\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Hiq nga përzgjedhja \"Gishti poshtë\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Përzgjidh \"Gishtin poshtë\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Mos përsërit asnjë"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Përsërit të gjitha"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Përsërit një"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aktivizo përzierjen"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Çaktivizo përzierjen"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivizo \"Cilësinë e lartë\""</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Çaktivizo \"Cilësinë e lartë\""</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivizo titrat"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Çaktivizo titrat me sekuencë kohore"</string>
+</resources>
diff --git a/v17/leanback/res/values-sr/strings.xml b/v17/leanback/res/values-sr/strings.xml
index 771067c..bb5c32d 100644
--- a/v17/leanback/res/values-sr/strings.xml
+++ b/v17/leanback/res/values-sr/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Говорите да бисте претраживали"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Претражите <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Изговорите да бисте претражили <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Пусти"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Паузирај"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Премотај унапред"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Премотај унапред %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Премотај уназад"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Премотај уназад %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Прескочи следећу"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Прескочи претходну"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Још радњи"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Опозови избор палца нагоре"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Изабери палац нагоре"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Опозови избор палца надоле"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Изабери палац надоле"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Не понављај ниједну"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Понови све"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Понови једну"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Омогући насумичну репродукцију"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Онемогући насумичну репродукцију"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Омогући висок квалитет"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Онемогући висок квалитет"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Омогући титлове"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Онемогући титлове"</string>
</resources>
diff --git a/v17/leanback/res/values-sv/strings.xml b/v17/leanback/res/values-sv/strings.xml
index 8b64837..1a8e757 100644
--- a/v17/leanback/res/values-sv/strings.xml
+++ b/v17/leanback/res/values-sv/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Säg det du söker efter"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Sök i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Tala för att söka i <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Spela upp"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Pausa"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Snabbspola framåt"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Spola framåt %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Spola tillbaka"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Spola tillbaka %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Hoppa till nästa"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Hoppa till föregående"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Fler åtgärder"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Avmarkera tummen upp"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Markera tummen upp"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Avmarkera tummen ned"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Markera tummen ned"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Upprepa inga"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Upprepa alla"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Upprepa en"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Blanda spår"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Blanda inte spår"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Aktivera hög kvalitet"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Inaktivera hög kvalitet"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Aktivera textning"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Inaktivera textning"</string>
</resources>
diff --git a/v17/leanback/res/values-sw/strings.xml b/v17/leanback/res/values-sw/strings.xml
index 23d2641..17c7480 100644
--- a/v17/leanback/res/values-sw/strings.xml
+++ b/v17/leanback/res/values-sw/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Tamka ili utafute"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Tafuta <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Tamka ili utafute <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Google Play"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Sitisha"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Peleka mbele Haraka"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Peleka Mbele %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Rudisha nyuma"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Peleka nyuma %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Ruka Inayofuata"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Ruka Iliyotangulia"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Vitendo zaidi"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ondoa Uteuzi wa Bomba"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Teua Bomba"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Ondoa Uteuzi wa Si Bomba"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Teua Si Bomba"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Usirudie Yoyote"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Rudia zote"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Rudia Moja"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Washa Kuchanganya"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Zima Kuchanganya"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Washa Ubora wa Juu"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Zima Ubora wa Juu"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Washa manukuu"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Zima manukuu"</string>
</resources>
diff --git a/v17/leanback/res/values-ta-rIN/strings.xml b/v17/leanback/res/values-ta-rIN/strings.xml
index 9533839..9472522 100644
--- a/v17/leanback/res/values-ta-rIN/strings.xml
+++ b/v17/leanback/res/values-ta-rIN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"தேட, பேசவும்"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ஐத் தேடுக"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ஐத் தேட, பேசவும்"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"இயக்கு"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"இடைநிறுத்து"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"வேகமாக முன் நகர்த்து"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX வேகத்தில் முன்செல்"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"வேகமாக பின் நகர்த்து"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX வேகத்தில் பின்செல்"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"அடுத்ததைத் தவிர்"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"முந்தையதைத் தவிர்"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"மேலும் செயல்கள்"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"தரமேற்றத்தைத் திரும்பப் பெறு"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"தரமேற்றத்தைத் தேர்ந்தெடு"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"தரமிறக்கத்தைத் திரும்பப் பெறு"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"தரமிறக்கத்தைத் தேர்ந்தெடு"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"எதையும் மீண்டும் இயக்காதே"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"அனைத்தையும் மீண்டும் இயக்கு"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ஒன்றை மட்டும் மீண்டும் இயக்கு"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"கலைத்து இயக்கு"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"கலைக்காமல் இயக்கு"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"உயர் தரத்தை இயக்கு"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"உயர் தரத்தை முடக்கு"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"விரிவான வசனங்களை இயக்கு"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"விரிவான வசனங்களை முடக்கு"</string>
</resources>
diff --git a/v17/leanback/res/values-te-rIN/strings.xml b/v17/leanback/res/values-te-rIN/strings.xml
index 2715f97..f71e8cb 100644
--- a/v17/leanback/res/values-te-rIN/strings.xml
+++ b/v17/leanback/res/values-te-rIN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"శోధించడానికి చదివి వినిపించండి"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ని శోధించండి"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>ని శోధించడానికి చదివి వినిపించండి"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"ప్లే చేయి"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"పాజ్ చేయి"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"వేగంగా ఫార్వార్డ్ చేయి"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX ఫాస్ట్ ఫార్వార్డ్ చేయి"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"రివైండ్ చేయి"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX రివైండ్ చేయి"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"తదుపరి దానికి దాటవేయి"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"మునుపటి దానికి దాటవేయి"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"మరిన్ని చర్యలు"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"విజయ సంకేతం ఎంపికను తీసివేయి"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"విజయ సంకేతాన్ని ఎంచుకోండి"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"ఓటమి సంకేతం ఎంపికను తీసివేయి"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"ఓటమి సంకేతాన్ని ఎంచుకోండి"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ఏదీ పునరావృతం చేయవద్దు"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"అన్నీ పునరావృతం చేయి"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ఒకదాన్ని పునరావృతం చేయి"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"షఫుల్ను ప్రారంభించు"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"షఫుల్ను నిలిపివేయి"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"అధిక నాణ్యతను ప్రారంభించు"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"అధిక నాణ్యతను నిలిపివేయి"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"సంవృత శీర్షికలను ప్రారంభించు"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"సంవృత శీర్షికలను నిలిపివేయి"</string>
</resources>
diff --git a/v17/leanback/res/values-th/strings.xml b/v17/leanback/res/values-th/strings.xml
index 09922aa..581bac0 100644
--- a/v17/leanback/res/values-th/strings.xml
+++ b/v17/leanback/res/values-th/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"พูดเพื่อค้นหา"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"ค้นหา <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"พูดเพื่อค้นหา <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"เล่น"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"หยุดชั่วคราว"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"กรอไปข้างหน้า"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"กรอไปข้างหน้า %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"กรอกลับ"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"กรอกลับ %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"ข้ามไปรายการถัดไป"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"ข้ามไปรายการก่อนหน้า"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"การทำงานเพิ่มเติม"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"ยกเลิกการเลือกว่าชอบ"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"เลือกว่าชอบ"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"ยกเลิกการเลือกว่าไม่ชอบ"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"เลือกว่าไม่ชอบ"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"ไม่เล่นซ้ำ"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"เล่นซ้ำทั้งหมด"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"เล่นซ้ำรายการเดียว"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"เปิดใช้การสุ่มเพลง"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"ปิดใช้การสุ่มเพลง"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"เปิดใช้คุณภาพสูง"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"ปิดใช้คุณภาพสูง"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"เปิดใช้คำบรรยาย"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"ปิดใช้คำบรรยาย"</string>
</resources>
diff --git a/v17/leanback/res/values-tl/strings.xml b/v17/leanback/res/values-tl/strings.xml
index 43eaad2..c4e15ec 100644
--- a/v17/leanback/res/values-tl/strings.xml
+++ b/v17/leanback/res/values-tl/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Magsalita upang maghanap"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Hanapin ang <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Magsalita upang hanapin ang <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"I-play"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"I-pause"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"I-fast Forward"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"I-fast Forward %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"I-rewind"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"I-rewind %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Laktawan ang Susunod"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Laktawan ang Nakaraan"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Higit Pang Mga Pagkilos"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Alisin sa Pagkakapili ang Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Piliin ang Thumb Up"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Alisin sa Pagkakapili ang Thumb Down"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Piliin ang Thumb Down"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Walang Uulitin"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Ulitin Lahat"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Ulitin ang Isa"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"I-enable ang Shuffle"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"I-disable ang Shuffle"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"I-enable ang Mataas na Kalidad"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"I-disable ang Mataas na Kalidad"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"I-enable ang Paglalagay ng Subtitle"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"I-disable ang Paglalagay ng Subtitle"</string>
</resources>
diff --git a/v17/leanback/res/values-tr/strings.xml b/v17/leanback/res/values-tr/strings.xml
index cfa5167..4671058 100644
--- a/v17/leanback/res/values-tr/strings.xml
+++ b/v17/leanback/res/values-tr/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Arama yapmak için konuşun"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Ara: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Aramak için konuşun: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Oynat"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Duraklat"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"İleri Sar"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX İleri Sar"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Geri Sar"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX Geri Sar"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Sonrakine Atla"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Öncekine Atla"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Diğer İşlemler"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Beğenme Seçimini Kaldır"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Beğenmeyi Seç"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Beğenmeme Seçimini Kaldır"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Beğenmemeyi Seç"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Hiçbirini Tekrarlama"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Tümünü Tekrarla"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Birini Tekrarla"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Karıştırmayı Etkinleştir"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Karıştırmayı Devre Dışı Bırak"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Yüksek Kalitede Oynatmayı Etkinleştir"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yüksek Kalitede Oynatmayı Devre Dışı Bırak"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Altyazıları Etkinleştir"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Altyazıları Devre Dışı Bırak"</string>
</resources>
diff --git a/v17/leanback/res/values-uk/strings.xml b/v17/leanback/res/values-uk/strings.xml
index c67bc8b..79b2782 100644
--- a/v17/leanback/res/values-uk/strings.xml
+++ b/v17/leanback/res/values-uk/strings.xml
@@ -21,5 +21,29 @@
<string name="lb_search_bar_hint" msgid="8325490927970116252">"Пошук"</string>
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Продиктуйте пошуковий запит"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Шукати: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
- <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Продиктуйте, щоб шукати: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Продиктуйте запит для пошуку: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Відтворити"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Призупинити"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Перемотати вперед"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Перемотати вперед %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Перемотати назад"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Перемотати назад %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Пропустити наступний елемент"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Пропустити попередній елемент"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Інші дії"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Скасувати оцінку \"Подобається\""</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Вибрати оцінку \"Подобається\""</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Скасувати оцінку \"Не подобається\""</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Вибрати оцінку \"Не подобається\""</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Не повторювати"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Повторити все"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Повторити один елемент"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Увімкнути перемішування"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Вимкнути перемішування"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Увімкнути високу якість"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Вимкнути високу якість"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Увімкнути субтитри"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Вимкнути субтитри"</string>
</resources>
diff --git a/v17/leanback/res/values-ur-rPK/strings.xml b/v17/leanback/res/values-ur-rPK/strings.xml
index bcc9fde..b670251 100644
--- a/v17/leanback/res/values-ur-rPK/strings.xml
+++ b/v17/leanback/res/values-ur-rPK/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"تلاش کرنے کیلئے بولیں"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> تلاش کریں"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> تلاش کرنے کیلئے بولیں"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"چلائیں"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"موقوف کریں"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"تیزی سے فارورڈ کریں"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"تیزی سے فارورڈ کریں %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"ریوائینڈ کریں"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"ریوائنڈ کریں %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"اگلے پر جائیں"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"پچھلے پر جائیں"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"مزید کارروائیاں"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"اوپر کی طرف والے انگوٹھے کے نشان کو غیر منتخب کریں"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"اوپر کی طرف والے انگوٹھے کے نشان کو منتخب کریں"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"نیچے کی طرف والے انگوٹھے کے نشان کو غیر منتخب کریں"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"نیچے کی طرف والے انگوٹھے کے نشان کو منتخب کریں"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"کسی کو نہ دہرائیں"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"سبھی کو دہرائیں"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"ایک کو دہرائیں"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"شفل کو فعال کریں"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"شفل کو غیر فعال کریں"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"اعلی معیار کو فعال کریں"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"اعلی معیار کو غیر فعال کریں"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"سب ٹائٹلز کو فعال کریں"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"سب ٹائٹلز کو غیر فعال کریں"</string>
</resources>
diff --git a/v17/leanback/res/values-uz-rUZ/strings.xml b/v17/leanback/res/values-uz-rUZ/strings.xml
index 95ae803..235d88f 100644
--- a/v17/leanback/res/values-uz-rUZ/strings.xml
+++ b/v17/leanback/res/values-uz-rUZ/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Qidirish uchun gapiring"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Qidirish: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Qidirish uchun ayting: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Ijro qilish"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"To‘xtatib turish"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Oldinga o‘tkazish"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$dX tezlikda oldinga o‘tkazish"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Orqaga qaytarish"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$dX tezlikda orqaga qaytarish"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Keyingisiga o‘tish"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Avvalgisiga qaytish"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Boshqa amallar"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Ijobiy baho tanlovini bekor qilish"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Ijobiy bahoni tanlash"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Salbiy baho tanlovini bekor qilish"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Salbiy bahoni tanlash"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Takrorlamaslik"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Barchasini takrorlash"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Bir marta takrorlash"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Aralashtirish funksiyasini yoqish"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Aralashtirish funksiyasini o‘chirish"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Yuqori sifatni yoqish"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Yuqori sifatni o‘chirib qo‘yish"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Taglavhalarni yoqish"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Taglavhalarni o‘chirib qo‘yish"</string>
</resources>
diff --git a/v17/leanback/res/values-vi/strings.xml b/v17/leanback/res/values-vi/strings.xml
index 2da6873..201d137 100644
--- a/v17/leanback/res/values-vi/strings.xml
+++ b/v17/leanback/res/values-vi/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Nói để tìm kiếm"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Tìm kiếm <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Nói để tìm kiếm <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Phát"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Tạm dừng"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Tua nhanh"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Tua đi %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Tua lại"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Tua lại %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Chuyển đến mục tiếp theo"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Chuyển về mục trước"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Tác vụ khác"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Bỏ chọn thích"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Chọn thích"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Bỏ chọn không thích"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Chọn không thích"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Không lặp lại"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Lặp lại tất cả"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Lặp lại một mục"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Bật phát ngẫu nhiên"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Tắt phát ngẫu nhiên"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Bật chế độ chất lượng cao"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Tắt chế độ chất lượng cao"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Bật phụ đề"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Tắt phụ đề"</string>
</resources>
diff --git a/v17/leanback/res/values-zh-rCN/strings.xml b/v17/leanback/res/values-zh-rCN/strings.xml
index 7f91918..276e7bb 100644
--- a/v17/leanback/res/values-zh-rCN/strings.xml
+++ b/v17/leanback/res/values-zh-rCN/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"说话即可开始搜索"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"搜索<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"说话即可在<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>中搜索"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$d 倍速"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$d 倍速"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"播放"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"暂停"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"快进"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"%1$d 倍速快进"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"快退"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"%1$d 倍速快退"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"跳至下一个"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"跳至上一个"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"更多操作"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"取消选择顶操作"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"选择顶操作"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"取消选择踩操作"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"选择踩操作"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"不重复播放"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"重复播放全部"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"重复播放一项"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"开启随机播放"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"关闭随机播放"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"开启高画质模式"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"关闭高画质模式"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"开启字幕"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"关闭字幕"</string>
</resources>
diff --git a/v17/leanback/res/values-zh-rHK/strings.xml b/v17/leanback/res/values-zh-rHK/strings.xml
index 6e32bf5..5e87989 100644
--- a/v17/leanback/res/values-zh-rHK/strings.xml
+++ b/v17/leanback/res/values-zh-rHK/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"使用語音搜尋"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"使用語音搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"播放"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"暫停"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"向前快轉"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"快轉 %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"向後倒轉"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"倒帶 %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"移至下一個媒體項目"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"移至上一個媒體項目"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"更多動作"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"取消選取喜歡"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"選取喜歡"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"取消選取不喜歡"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"選取不喜歡"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"不重複播放"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"重複播放所有媒體項目"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"重複播放一個媒體項目"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"啟用隨機播放"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"停用隨機播放"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"啟用高畫質"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"停用高畫質"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
</resources>
diff --git a/v17/leanback/res/values-zh-rTW/strings.xml b/v17/leanback/res/values-zh-rTW/strings.xml
index 6e32bf5..67efc40 100644
--- a/v17/leanback/res/values-zh-rTW/strings.xml
+++ b/v17/leanback/res/values-zh-rTW/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"使用語音搜尋"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"使用語音搜尋「<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>」"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"播放"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"暫停"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"向前快轉"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"快轉 %1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"倒轉"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"倒轉 %1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"跳至下一個項目"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"跳至上一個項目"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"更多動作"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"取消選取喜歡"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"選取喜歡"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"取消選取不喜歡"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"選取不喜歡"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"不重複播放"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"重複播放所有項目"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"重複播放單一項目"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"啟用隨機播放"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"停用隨機播放"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"啟用高品質播放"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"停用高品質播放"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"啟用字幕"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"停用字幕"</string>
</resources>
diff --git a/v17/leanback/res/values-zu/strings.xml b/v17/leanback/res/values-zu/strings.xml
index 4168b19..f17455d 100644
--- a/v17/leanback/res/values-zu/strings.xml
+++ b/v17/leanback/res/values-zu/strings.xml
@@ -22,4 +22,28 @@
<string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"Khuluma ukuze useshe"</string>
<string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"Sesha i-<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
<string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"Khuluma ukuze useshe i-<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+ <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+ <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+ <string name="lb_playback_controls_play" msgid="731953341987346903">"Dlala"</string>
+ <string name="lb_playback_controls_pause" msgid="6189521112079849518">"Misa isikhashana"</string>
+ <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"Iya phambili ngokushesha"</string>
+ <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"Mikisa phambili ngokushesha i-%1$dX"</string>
+ <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"Buyisela emuva"</string>
+ <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"Mikisa emuva i-%1$dX"</string>
+ <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"Yeqa okulandelayo"</string>
+ <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"Yeqa kwangaphambilini"</string>
+ <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"Izenzo eziningi"</string>
+ <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"Susa ukukhetha isithupha saphezulu"</string>
+ <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"Khetha isithupha saphezulu"</string>
+ <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"Susa ukukhetha isithupha saphansi"</string>
+ <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"Khetha isithupha saphansi"</string>
+ <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"Ungaphindi lutho"</string>
+ <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"Phinda konke"</string>
+ <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"Phida okukodwa"</string>
+ <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"Nika amandla ukushova"</string>
+ <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"Khubaza ukushova"</string>
+ <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"Nika amandla ikhwalithi ephezulu"</string>
+ <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"Khubaza ikhwalithi ephezulu"</string>
+ <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"Nika amandla imibhalo engezansi"</string>
+ <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"Khubaza imihbalo engezansi"</string>
</resources>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index 1b77694..656e38e 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -431,5 +431,27 @@
</declare-styleable>
+ <attr name="cardGravity">
+ <!-- Push child views to the left of the container. -->
+ <flag name="left" value="0x03" />
+ <!-- Push child views to the right of the container. -->
+ <flag name="right" value="0x05" />
+ <!-- Push child views to the beginning of the container. -->
+ <flag name="start" value="0x00800003" />
+ <!-- Push child views to the end of the container. -->
+ <flag name="end" value="0x00800005" />
+ </attr>
+
+ <declare-styleable name="StackedLayout">
+ <!-- Defines the width of child views in this layout -->
+ <attr name="cardWidth" format="dimension" />
+ <!-- Defines the distance to shift child views away from the edge when another child
+ is added -->
+ <attr name="stackShift" format="dimension" />
+ <!-- Defines the amount to increment the elevation of each added child -->
+ <attr name="elevationIncrement" format="dimension" />
+ <!-- Defines which edge child views are laid out on -->
+ <attr name="cardGravity" />
+ </declare-styleable>
</resources>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java b/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
index 4eec366..1b10741 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
@@ -15,6 +15,7 @@
import java.lang.ref.WeakReference;
+import android.support.annotation.ColorInt;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@@ -964,7 +965,7 @@
* Sets the background to the given color. The timing for when this becomes
* visible in the app is undefined and may take place after a small delay.
*/
- public void setColor(int color) {
+ public void setColor(@ColorInt int color) {
if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
mBackgroundColor = color;
@@ -1116,6 +1117,7 @@
/**
* Returns the current background color.
*/
+ @ColorInt
public final int getColor() {
return mBackgroundColor;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 4860018..5f8cd51 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -13,6 +13,7 @@
*/
package android.support.v17.leanback.app;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.support.v17.leanback.transition.LeanbackTransitionHelper;
import android.support.v17.leanback.transition.TransitionHelper;
@@ -276,7 +277,7 @@
*
* @param color The color to use as the brand color of the fragment.
*/
- public void setBrandColor(int color) {
+ public void setBrandColor(@ColorInt int color) {
mBrandColor = color;
mBrandColorSet = true;
@@ -289,6 +290,7 @@
* Returns the brand color for the browse fragment.
* The default is transparent.
*/
+ @ColorInt
public int getBrandColor() {
return mBrandColor;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index bfa83e8..a98e1ea 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -15,6 +15,7 @@
*/
package android.support.v17.leanback.app;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.support.v17.leanback.transition.LeanbackTransitionHelper;
import android.support.v17.leanback.transition.TransitionHelper;
@@ -278,7 +279,7 @@
*
* @param color The color to use as the brand color of the fragment.
*/
- public void setBrandColor(int color) {
+ public void setBrandColor(@ColorInt int color) {
mBrandColor = color;
mBrandColorSet = true;
@@ -291,6 +292,7 @@
* Returns the brand color for the browse fragment.
* The default is transparent.
*/
+ @ColorInt
public int getBrandColor() {
return mBrandColor;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
index d02ef97..6b6cc2e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
@@ -13,6 +13,7 @@
*/
package android.support.v17.leanback.app;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.BrowseFrameLayout;
import android.support.v17.leanback.widget.OnChildLaidOutListener;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
index 73d299c..0770761 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
@@ -15,6 +15,7 @@
*/
package android.support.v17.leanback.app;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.BrowseFrameLayout;
import android.support.v17.leanback.widget.OnChildLaidOutListener;
diff --git a/v17/leanback/src/android/support/v17/leanback/view/StackedLayout.java b/v17/leanback/src/android/support/v17/leanback/view/StackedLayout.java
new file mode 100644
index 0000000..56c4bad
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/view/StackedLayout.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.leanback.view;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.support.v17.leanback.R;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A ViewGroup which arranges its children in an overlapping stack with the most
+ * recently added view displayed at the top. Adding and removing views is animated.
+ *
+ * @attr ref R.styleable#StackedLayout_cardWidth
+ * @attr ref R.styleable#StackedLayout_stackShift
+ * @attr ref R.styleable#StackedLayout_elevationIncrement
+ * @attr ref R.styleable#StackedLayout_cardGravity
+ *
+ * @hide
+ */
+public class StackedLayout extends ViewGroup {
+
+ private int mCardWidth;
+ private int mStackShift;
+ private float mElevationIncrement;
+ private int mCardGravity;
+
+ private int mAddedViews = 0;
+ private int mRemovedViews = 0;
+ private List<View> mQueuedRemovedViews;
+ private Animator mCurrentAnimator;
+
+ private OnHierarchyChangeListener mHierarchyChangeListener;
+ private final OnHierarchyChangeListener mHierarchyChangeListenerInternal =
+ new OnHierarchyChangeInternalListener();
+
+ public StackedLayout(Context context) {
+ this(context, null);
+ }
+
+ public StackedLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public StackedLayout(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.StackedLayout, defStyleAttr, 0);
+ mCardWidth = Math.round(a.getDimension(R.styleable.StackedLayout_cardWidth, 0));
+ mStackShift = Math.round(a.getDimension(R.styleable.StackedLayout_stackShift, 0));
+ mElevationIncrement = a.getDimension(R.styleable.StackedLayout_elevationIncrement, 0);
+ mCardGravity = a.getInt(R.styleable.StackedLayout_cardGravity, GravityCompat.END);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ super.setOnHierarchyChangeListener(mHierarchyChangeListenerInternal);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ super.setOnHierarchyChangeListener(null);
+ }
+
+ @Override
+ public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
+ mHierarchyChangeListener = listener;
+ }
+
+ @Override
+ protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ return false;
+ }
+ final View lastChild = getChildAt(childCount - 1);
+ return lastChild.requestFocus(direction, previouslyFocusedRect);
+ }
+
+ @Override
+ public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ // We only want to be able to focus the [child views of] the last child
+ if (getChildCount() == 0) {
+ return;
+ }
+
+ final View lastChild = getChildAt(getChildCount() - 1);
+ lastChild.addFocusables(views, direction, focusableMode);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ final int width;
+ final int height;
+
+ switch (widthMode) {
+ case MeasureSpec.EXACTLY:
+ case MeasureSpec.AT_MOST:
+ width = widthSize;
+ break;
+ case MeasureSpec.UNSPECIFIED:
+ default:
+ width = ViewCompat.getMinimumWidth(this);
+ break;
+ }
+
+ switch (heightMode) {
+ case MeasureSpec.EXACTLY:
+ case MeasureSpec.AT_MOST:
+ height = heightSize;
+ break;
+ case MeasureSpec.UNSPECIFIED:
+ default:
+ height = ViewCompat.getMinimumHeight(this);
+ break;
+ }
+
+ setMeasuredDimension(width, height);
+
+ final int childWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(mCardWidth, MeasureSpec.EXACTLY);
+ final int childHeightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(height - getPaddingTop() - getPaddingBottom(),
+ MeasureSpec.AT_MOST);
+
+ measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(getContext(), attrs);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return p instanceof LayoutParams;
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ return new LayoutParams(p);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final boolean rightEdge =
+ (GravityCompat.getAbsoluteGravity(mCardGravity, ViewCompat.getLayoutDirection(this))
+ & Gravity.RIGHT) == Gravity.RIGHT;
+
+ layoutInternal(l, t, r, b, rightEdge);
+ if (mAddedViews != 0 || mRemovedViews != 0) {
+ if (mCurrentAnimator != null) {
+ mCurrentAnimator.cancel();
+ mCurrentAnimator = null;
+ }
+
+ final int initialPositions[] = getChildLeftPositions();
+
+ mAddedViews = 0;
+ mRemovedViews = 0;
+ layoutInternal(l, t, r, b, rightEdge);
+
+ final int finalPositions[] = getChildLeftPositions();
+
+
+ final int childCount = getChildCount();
+ final List<Animator> animators = new ArrayList<>(childCount);
+
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
+ final View child = getChildAt(childIndex);
+ // Want: initialPos = finalPos + translationX
+ // Thus: initialPos - finalPos = translationX
+ // Plus any current translation in case we interrupted an animation in progress
+
+ final int newTranslationX = initialPositions[childIndex]
+ - finalPositions[childIndex] + Math.round(child.getTranslationX());
+
+ child.setTranslationX(newTranslationX);
+
+ if (newTranslationX != 0) {
+ // Animate to zero
+ animators.add(ObjectAnimator.ofFloat(child, "translationX", 0));
+ }
+ }
+
+ if (mQueuedRemovedViews != null) {
+ for (final View child : mQueuedRemovedViews) {
+ // Want: initialPos = finalPos + translationX
+ // Thus: initialPos - finalPos = translationX
+ // Plus any current translation in case we interrupted an animation in progress
+
+ final int newTranslationX;
+
+ if (rightEdge) {
+ newTranslationX = child.getLeft() - getRight()
+ + Math.round(child.getTranslationX());
+ // Move the child to the new position and set the translation
+ child.offsetLeftAndRight(getRight() - child.getLeft());
+ } else {
+ newTranslationX = child.getLeft() - getLeft() + child.getWidth()
+ + Math.round(child.getTranslationX());
+ // Move the child to the new position and set the translation
+ child.offsetLeftAndRight(getLeft() - child.getWidth() - child.getLeft());
+ }
+
+ child.setTranslationX(newTranslationX);
+
+ // Animate to zero
+ final Animator animator = ObjectAnimator.ofFloat(child, "translationX", 0);
+ animator.addListener(new RemovalAnimationListener(child));
+ animators.add(animator);
+ }
+ mQueuedRemovedViews = null;
+ }
+
+ final AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(animators);
+ mCurrentAnimator = animatorSet;
+ mCurrentAnimator.start();
+ }
+
+ }
+
+ private int[] getChildLeftPositions() {
+ final int childCount = getChildCount();
+ final int positions[] = new int[childCount];
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
+ positions[childIndex] = getChildAt(childIndex).getLeft();
+ }
+ return positions;
+ }
+
+ private void layoutInternal(int l, int t, int r, int b, boolean rightEdge) {
+ final int parentLeft = getPaddingLeft();
+ final int parentRight = r - l - getPaddingRight();
+
+ final int parentTop = getPaddingTop();
+ final int parentBottom = b - t - getPaddingBottom();
+
+ final float baseElevation = ViewCompat.getElevation(this);
+
+ final int childCount = getChildCount();
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
+ final View child = getChildAt(childIndex);
+ if (child.getVisibility() != GONE) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ final int width = Math.round(mCardWidth);
+ final int height = child.getMeasuredHeight();
+
+ final int childLeft;
+ if (childIndex >= childCount - mAddedViews) {
+ // This is a freshly added view, start it off the edge of the container.
+ if (rightEdge) {
+ childLeft = parentRight;
+ } else {
+ childLeft = parentLeft - width;
+ }
+ } else {
+ // This is an existing view, just place it normally. If there are added/removed
+ // views, then place it as if those views have not yet been added/removed.
+ if (rightEdge) {
+ childLeft = parentRight - width - lp.rightMargin -
+ (childCount - childIndex - (1 + mAddedViews - mRemovedViews))
+ * mStackShift;
+ } else {
+ childLeft = parentLeft + lp.leftMargin +
+ (childCount - childIndex - (1 + mAddedViews - mRemovedViews))
+ * mStackShift;
+ }
+ }
+ final int childTop = parentTop + lp.topMargin;
+
+ child.layout(childLeft, childTop, childLeft + width, childTop + height);
+
+ ViewCompat.setElevation(child,
+ baseElevation + (childIndex + 1) * mElevationIncrement);
+ }
+ }
+ }
+
+ public class LayoutParams extends MarginLayoutParams {
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ public LayoutParams(MarginLayoutParams source) {
+ super(source);
+ }
+
+ public LayoutParams(ViewGroup.LayoutParams source) {
+ super(source);
+ }
+ }
+
+ private class OnHierarchyChangeInternalListener implements OnHierarchyChangeListener {
+
+ @Override
+ public void onChildViewAdded(View parent, View child) {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount - 1; i++) {
+ final View oldChild = getChildAt(i);
+ oldChild.clearFocus();
+ }
+ mAddedViews++;
+ if (mHierarchyChangeListener != null) {
+ mHierarchyChangeListener.onChildViewAdded(parent, child);
+ }
+ }
+
+ @Override
+ public void onChildViewRemoved(View parent, final View child) {
+ if (mHierarchyChangeListener != null) {
+ mHierarchyChangeListener.onChildViewRemoved(parent, child);
+ }
+ mRemovedViews++;
+ if (ViewGroupOverlayHelper.supportsOverlay()) {
+ ViewGroupOverlayHelper.addChildToOverlay(StackedLayout.this, child);
+ if (mQueuedRemovedViews == null) {
+ mQueuedRemovedViews = new ArrayList<>(1);
+ }
+ mQueuedRemovedViews.add(child);
+ }
+ }
+ }
+
+ private class RemovalAnimationListener implements Animator.AnimatorListener {
+ private final View mView;
+
+ public RemovalAnimationListener(View view) {
+ mView = view;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ ViewGroupOverlayHelper.removeChildFromOverlay(StackedLayout.this, mView);
+ animation.removeListener(this);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ // Re-add the view to the queued list so that the next animation continues
+ // animating it away
+ if (mQueuedRemovedViews == null) {
+ mQueuedRemovedViews = new ArrayList<>(1);
+ }
+ mQueuedRemovedViews.add(mView);
+ animation.removeListener(this);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {}
+
+ @Override
+ public String toString() {
+ return getClass().getName() + " [" + mView.toString() + "]";
+ }
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/view/ViewGroupOverlayHelper.java b/v17/leanback/src/android/support/v17/leanback/view/ViewGroupOverlayHelper.java
new file mode 100644
index 0000000..18e3534
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/view/ViewGroupOverlayHelper.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.leanback.view;
+
+import android.os.Build;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ViewGroupOverlayHelper {
+
+ public interface Impl {
+ void addChildToOverlay(ViewGroup parent, View child);
+ void removeChildFromOverlay(ViewGroup parent, View child);
+ }
+
+ private static class ImplStub implements Impl {
+
+ @Override
+ public void addChildToOverlay(ViewGroup parent, View child) {}
+
+ @Override
+ public void removeChildFromOverlay(ViewGroup parent, View child) {}
+ }
+
+ private static class ImplJbmr2 implements Impl {
+
+ @Override
+ public void addChildToOverlay(ViewGroup parent, View child) {
+ ViewGroupOverlayHelperJbmr2.addChildToOverlay(parent, child);
+ }
+
+ @Override
+ public void removeChildFromOverlay(ViewGroup parent, View child) {
+ ViewGroupOverlayHelperJbmr2.removeChildFromOverlay(parent, child);
+ }
+ }
+
+ private static Impl sInstance;
+
+ private static Impl getInstance() {
+ if (sInstance == null) {
+ if (Build.VERSION.SDK_INT >= 18) {
+ sInstance = new ImplJbmr2();
+ } else {
+ sInstance = new ImplStub();
+ }
+ }
+ return sInstance;
+ }
+
+ public static boolean supportsOverlay() {
+ return Build.VERSION.SDK_INT >= 18;
+ }
+
+ public static void addChildToOverlay(ViewGroup parent, View child) {
+ getInstance().addChildToOverlay(parent, child);
+ }
+
+ public static void removeChildFromOverlay(ViewGroup parent, View child) {
+ getInstance().removeChildFromOverlay(parent, child);
+ }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
index be9a263..34c2004 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
@@ -21,6 +21,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -326,7 +327,7 @@
/**
* Sets the background color. If not set, a default from the theme will be used.
*/
- public void setBackgroundColor(int color) {
+ public void setBackgroundColor(@ColorInt int color) {
mBackgroundColor = color;
mBackgroundColorSet = true;
}
@@ -335,6 +336,7 @@
* Returns the background color. If no background color was set, transparent
* is returned.
*/
+ @ColorInt
public int getBackgroundColor() {
return mBackgroundColor;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
index 48e491b..15943b4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
@@ -529,6 +529,8 @@
Context context = iconView.getContext();
icon = action.getIcon();
if (icon != null) {
+ // setImageDrawable resets the drawable's level unless we set the view level first.
+ iconView.setImageLevel(icon.getLevel());
iconView.setImageDrawable(icon);
iconView.setVisibility(View.VISIBLE);
} else {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
index eaab7c0..2c1c7e0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ImageCardView.java
@@ -16,6 +16,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -169,8 +170,8 @@
/**
* Sets the info area background color.
- */
- public void setInfoAreaBackgroundColor(int color) {
+ */
+ public void setInfoAreaBackgroundColor(@ColorInt int color) {
if (mInfoArea != null) {
mInfoArea.setBackgroundColor(color);
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
index 72352f9..f1db00b 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
@@ -20,6 +20,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -227,7 +228,7 @@
return mMoreActionsEnabled;
}
- public void setProgressColor(ViewHolder vh, int color) {
+ public void setProgressColor(ViewHolder vh, @ColorInt int color) {
Drawable drawable = new ClipDrawable(new ColorDrawable(color),
Gravity.LEFT, ClipDrawable.HORIZONTAL);
((LayerDrawable) vh.mProgressBar.getProgressDrawable())
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
index f6ceacb..b43fdb7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
@@ -14,6 +14,7 @@
package android.support.v17.leanback.widget;
import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.ControlBarPresenter.OnControlClickedListener;
import android.support.v17.leanback.widget.ControlBarPresenter.OnControlSelectedListener;
@@ -231,7 +232,7 @@
/**
* Sets the background color. If not set, a default from the theme will be used.
*/
- public void setBackgroundColor(int color) {
+ public void setBackgroundColor(@ColorInt int color) {
mBackgroundColor = color;
mBackgroundColorSet = true;
}
@@ -240,6 +241,7 @@
* Returns the background color. If no background color was set, transparent
* is returned.
*/
+ @ColorInt
public int getBackgroundColor() {
return mBackgroundColor;
}
@@ -248,7 +250,7 @@
* Sets the primary color for the progress bar. If not set, a default from
* the theme will be used.
*/
- public void setProgressColor(int color) {
+ public void setProgressColor(@ColorInt int color) {
mProgressColor = color;
mProgressColorSet = true;
}
@@ -257,6 +259,7 @@
* Returns the primary color for the progress bar. If no color was set, transparent
* is returned.
*/
+ @ColorInt
public int getProgressColor() {
return mProgressColor;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java b/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java
index 4de58ea..a8ea24c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowContainerView.java
@@ -17,6 +17,7 @@
import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -77,7 +78,7 @@
invalidate();
}
- public void setForegroundColor(int color) {
+ public void setForegroundColor(@ColorInt int color) {
if (mForeground instanceof ColorDrawable) {
((ColorDrawable) mForeground.mutate()).setColor(color);
invalidate();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java
index 46293ea..a060ec0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -63,7 +64,7 @@
*
* @param color The main search orb color.
*/
- public Colors(int color) {
+ public Colors(@ColorInt int color) {
this(color, color);
}
@@ -74,7 +75,7 @@
* @param color The main search orb color.
* @param brightColor A brighter version of the search orb used for animation.
*/
- public Colors(int color, int brightColor) {
+ public Colors(@ColorInt int color, @ColorInt int brightColor) {
this(color, brightColor, Color.TRANSPARENT);
}
@@ -85,7 +86,7 @@
* @param brightColor A brighter version of the search orb used for animation.
* @param iconColor A color used to tint the search orb icon.
*/
- public Colors(int color, int brightColor, int iconColor) {
+ public Colors(@ColorInt int color, @ColorInt int brightColor, @ColorInt int iconColor) {
this.color = color;
this.brightColor = brightColor == color ? getBrightColor(color) : brightColor;
this.iconColor = iconColor;
@@ -94,16 +95,19 @@
/**
* The main color of the search orb.
*/
+ @ColorInt
public int color;
/**
* A brighter version of the search orb used for animation.
*/
+ @ColorInt
public int brightColor;
/**
* A color used to tint the search orb icon.
*/
+ @ColorInt
public int iconColor;
/**
@@ -294,7 +298,7 @@
* @deprecated Use {@link #setOrbColors(Colors)} instead.
*/
@Deprecated
- public void setOrbColor(int color, int brightColor) {
+ public void setOrbColor(@ColorInt int color, @ColorInt int brightColor) {
setOrbColors(new Colors(color, brightColor, Color.TRANSPARENT));
}
@@ -302,6 +306,7 @@
* Returns the orb color
* @return the RGBA color
*/
+ @ColorInt
public int getOrbColor() {
return mColors.color;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
index 2244f5e..ad82fd2 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
@@ -14,6 +14,7 @@
package android.support.v17.leanback.widget;
import android.content.Context;
+import android.support.annotation.ColorInt;
import android.support.v17.leanback.R;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -216,7 +217,7 @@
/**
* Set color (with alpha) of the overlay.
*/
- public void setOverlayColor(int overlayColor) {
+ public void setOverlayColor(@ColorInt int overlayColor) {
if (mColorDimOverlay != null) {
mColorDimOverlay.setBackgroundColor(overlayColor);
}
diff --git a/v17/preference-leanback/Android.mk b/v17/preference-leanback/Android.mk
new file mode 100644
index 0000000..05a7a54
--- /dev/null
+++ b/v17/preference-leanback/Android.mk
@@ -0,0 +1,64 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the resources using the current SDK version.
+# We do this here because the final static library must be compiled with an older
+# SDK version than the resources. The resources library and the R class that it
+# contains will not be linked into the final static library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v17-preference-leanback-res
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, dummy)
+LOCAL_RESOURCE_DIR := \
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/recyclerview/res \
+ frameworks/support/v7/preference/res \
+ frameworks/support/v14/preference/res \
+ frameworks/support/v17/leanback/res \
+ $(LOCAL_PATH)/res
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay
+LOCAL_JAR_EXCLUDE_FILES := none
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Here is the final static library that apps can link against.
+# The R class is automatically excluded from the generated library.
+# Applications that use this library must specify LOCAL_RESOURCE_DIR
+# in their makefiles to include the resources in their package.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v17-preference-leanback
+LOCAL_SDK_VERSION := 17
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+# LOCAL_STATIC_JAVA_LIBRARIES :=
+LOCAL_JAVA_LIBRARIES := \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview \
+ android-support-v7-preference \
+ android-support-v14-preference \
+ android-support-v17-leanback \
+ android-support-annotations \
+ android-support-v17-preference-leanback-res
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# API Check
+# ---------------------------------------------
+support_module := $(LOCAL_MODULE)
+support_module_api_dir := $(LOCAL_PATH)/api
+support_module_src_files := $(LOCAL_SRC_FILES)
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
+support_module_java_packages := android.support.v17.preference
+include $(SUPPORT_API_CHECK)
diff --git a/v17/preference-leanback/AndroidManifest.xml b/v17/preference-leanback/AndroidManifest.xml
new file mode 100644
index 0000000..e2cfe35
--- /dev/null
+++ b/v17/preference-leanback/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.v17.preference"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="17" />
+ <application />
+</manifest>
diff --git a/v17/preference-leanback/api/current.txt b/v17/preference-leanback/api/current.txt
new file mode 100644
index 0000000..b31306c
--- /dev/null
+++ b/v17/preference-leanback/api/current.txt
@@ -0,0 +1,68 @@
+package android.support.v17.preference {
+
+ public abstract class BaseLeanbackPreferenceFragment extends android.support.v14.preference.PreferenceFragment {
+ ctor public BaseLeanbackPreferenceFragment();
+ }
+
+ public class LeanbackListPreferenceDialogFragment extends android.support.v17.preference.LeanbackPreferenceDialogFragment {
+ ctor public LeanbackListPreferenceDialogFragment();
+ method public static android.support.v17.preference.LeanbackListPreferenceDialogFragment newInstanceMulti(java.lang.String);
+ method public static android.support.v17.preference.LeanbackListPreferenceDialogFragment newInstanceSingle(java.lang.String);
+ method public android.support.v7.widget.RecyclerView.Adapter onCreateAdapter();
+ }
+
+ public class LeanbackListPreferenceDialogFragment.AdapterMulti extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+ ctor public LeanbackListPreferenceDialogFragment.AdapterMulti(java.lang.CharSequence[], java.lang.CharSequence[], java.util.Set<java.lang.String>);
+ method public int getItemCount();
+ method public void onBindViewHolder(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder, int);
+ method public android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method public void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+ }
+
+ public class LeanbackListPreferenceDialogFragment.AdapterSingle extends android.support.v7.widget.RecyclerView.Adapter implements android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+ ctor public LeanbackListPreferenceDialogFragment.AdapterSingle(java.lang.CharSequence[], java.lang.CharSequence[], java.lang.CharSequence);
+ method public int getItemCount();
+ method public void onBindViewHolder(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder, int);
+ method public android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+ method public void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+ }
+
+ public static class LeanbackListPreferenceDialogFragment.ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder implements android.view.View.OnClickListener {
+ ctor public LeanbackListPreferenceDialogFragment.ViewHolder(android.view.View, android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener);
+ method public android.view.ViewGroup getContainer();
+ method public android.widget.TextView getTitleView();
+ method public android.widget.Checkable getWidgetView();
+ method public void onClick(android.view.View);
+ }
+
+ public static abstract interface LeanbackListPreferenceDialogFragment.ViewHolder.OnItemClickListener {
+ method public abstract void onItemClick(android.support.v17.preference.LeanbackListPreferenceDialogFragment.ViewHolder);
+ }
+
+ public class LeanbackPreferenceDialogFragment extends android.app.Fragment {
+ ctor public LeanbackPreferenceDialogFragment();
+ method public android.support.v7.preference.DialogPreference getPreference();
+ method public android.support.v14.preference.PreferenceFragment getPreferenceFragment();
+ method public android.support.v17.preference.LeanbackSettingsFragment getSettingsFragment();
+ field public static final java.lang.String ARG_KEY = "key";
+ }
+
+ public static abstract interface LeanbackPreferenceDialogFragment.TargetFragment {
+ method public abstract android.support.v14.preference.PreferenceFragment getPreferenceFragment();
+ method public abstract android.support.v17.preference.LeanbackSettingsFragment getSettingsFragment();
+ }
+
+ public abstract class LeanbackPreferenceFragment extends android.support.v17.preference.BaseLeanbackPreferenceFragment {
+ ctor public LeanbackPreferenceFragment();
+ }
+
+ public abstract class LeanbackSettingsFragment extends android.app.Fragment {
+ ctor public LeanbackSettingsFragment();
+ method public boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
+ method public abstract void onPreferenceStartInitialScreen();
+ method public void startImmersiveFragment(android.app.Fragment, java.lang.String);
+ method public void startPreferenceFragment(android.app.Fragment, java.lang.String);
+ }
+
+}
+
diff --git a/v17/preference-leanback/api/removed.txt b/v17/preference-leanback/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v17/preference-leanback/api/removed.txt
diff --git a/v17/preference-leanback/build.gradle b/v17/preference-leanback/build.gradle
new file mode 100644
index 0000000..e8195da
--- /dev/null
+++ b/v17/preference-leanback/build.gradle
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+
+
+apply plugin: 'android-library'
+
+archivesBaseName = 'preference-leanback-v17'
+
+dependencies {
+ compile project(':support-v4')
+ compile project(':support-appcompat-v7')
+ compile project(':support-recyclerview-v7')
+ compile project(':support-preference-v7')
+ compile project(':support-preference-v14')
+ compile project(':support-leanback-v17')
+}
+
+android {
+ compileSdkVersion 'current'
+
+ sourceSets {
+ main.manifest.srcFile 'AndroidManifest.xml'
+ main.java.srcDir 'src'
+ main.res.srcDir 'res'
+ main.assets.srcDir 'assets'
+ main.resources.srcDir 'src'
+
+ // this moves src/instrumentTest to tests so all folders follow:
+ // tests/java, tests/res, tests/assets, ...
+ // This is a *reset* so it replaces the default paths
+ androidTest.setRoot('tests')
+ androidTest.java.srcDir 'tests/src'
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ lintOptions {
+ // TODO: fix errors and reenable.
+ abortOnError false
+ }
+}
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
new file mode 100644
index 0000000..ba8254b
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_fragment.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/lb_preference_decor_list_background"
+ android:orientation="vertical"
+ >
+
+ <TextView android:id="@+id/decor_title"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/lb_preference_decor_title_text_height"
+ android:background="?attr/defaultBrandColor"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center_vertical"
+ android:paddingTop="@dimen/lb_preference_decor_title_padding_top"
+ android:paddingStart="@dimen/lb_preference_decor_title_padding_start"
+ android:paddingEnd="@dimen/lb_preference_decor_title_padding_end"
+ android:singleLine="true"
+ android:textSize="@dimen/lb_preference_decor_title_text_size"
+ android:textColor="?android:attr/textColorPrimary"
+ />
+
+ <TextView
+ android:id="@android:id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="14dp"
+ android:paddingBottom="14dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="56dp"
+ android:visibility="gone" />
+
+ <android.support.v17.leanback.widget.VerticalGridView android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml b/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
new file mode 100644
index 0000000..3b1345c
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_item_multi.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
+ android:descendantFocusability="blocksDescendants"
+ android:orientation="horizontal">
+ <CheckBox
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical" />
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml b/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
new file mode 100644
index 0000000..eaf42a4
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_list_preference_item_single.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
+ android:descendantFocusability="blocksDescendants"
+ android:orientation="horizontal">
+ <RadioButton
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical" />
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preference_fragment.xml b/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
new file mode 100644
index 0000000..3279a42
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preference_fragment.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/lb_preference_decor_list_background"
+ android:orientation="vertical"
+ >
+
+ <TextView android:id="@+id/decor_title"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/lb_preference_decor_title_text_height"
+ android:background="?attr/defaultBrandColor"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center_vertical"
+ android:paddingTop="@dimen/lb_preference_decor_title_padding_top"
+ android:paddingStart="@dimen/lb_preference_decor_title_padding_start"
+ android:paddingEnd="@dimen/lb_preference_decor_title_padding_end"
+ android:singleLine="true"
+ android:textSize="@dimen/lb_preference_decor_title_text_size"
+ android:textColor="?android:attr/textColorPrimary"
+ />
+
+</LinearLayout>
diff --git a/v17/preference-leanback/res/layout/leanback_preferences_list.xml b/v17/preference-leanback/res/layout/leanback_preferences_list.xml
new file mode 100644
index 0000000..15ecebc
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_preferences_list.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<android.support.v17.leanback.widget.VerticalGridView
+ android:id="@+id/list"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/v17/preference-leanback/res/layout/leanback_settings_fragment.xml b/v17/preference-leanback/res/layout/leanback_settings_fragment.xml
new file mode 100644
index 0000000..5cf3e51
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_settings_fragment.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<android.support.v17.preference.LeanbackSettingsRootView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/settings_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/v17/preference-leanback/res/layout/leanback_settings_fragment_stack.xml b/v17/preference-leanback/res/layout/leanback_settings_fragment_stack.xml
new file mode 100644
index 0000000..568c41e
--- /dev/null
+++ b/v17/preference-leanback/res/layout/leanback_settings_fragment_stack.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<android.support.v17.leanback.view.StackedLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/settings_preference_stack"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:cardWidth="@dimen/lb_settings_card_width"
+ app:stackShift="@dimen/lb_settings_card_shift"
+ app:elevationIncrement="@dimen/lb_settings_card_elevation"
+ />
diff --git a/v17/preference-leanback/res/values/colors.xml b/v17/preference-leanback/res/values/colors.xml
new file mode 100644
index 0000000..de6c888
--- /dev/null
+++ b/v17/preference-leanback/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <color name="lb_preference_decor_list_background">#263238</color>
+</resources>
diff --git a/v17/preference-leanback/res/values/dimens.xml b/v17/preference-leanback/res/values/dimens.xml
new file mode 100644
index 0000000..c3e519f
--- /dev/null
+++ b/v17/preference-leanback/res/values/dimens.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+ <dimen name="lb_preference_decor_title_text_height">64dp</dimen>
+ <dimen name="lb_preference_decor_title_padding_top">27dp</dimen>
+ <dimen name="lb_preference_decor_title_padding_start">24dp</dimen>
+ <dimen name="lb_preference_decor_title_padding_end">56dp</dimen>
+ <dimen name="lb_preference_decor_title_text_size">20sp</dimen>
+
+ <dimen name="lb_settings_card_width">360dp</dimen>
+ <dimen name="lb_settings_card_shift">72dp</dimen>
+ <dimen name="lb_settings_card_elevation">12dp</dimen>
+</resources>
diff --git a/v17/preference-leanback/src/android/support/v17/preference/BaseLeanbackPreferenceFragment.java b/v17/preference-leanback/src/android/support/v17/preference/BaseLeanbackPreferenceFragment.java
new file mode 100644
index 0000000..40d9607
--- /dev/null
+++ b/v17/preference-leanback/src/android/support/v17/preference/BaseLeanbackPreferenceFragment.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.preference;
+
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+/**
+ * This fragment provides a preference fragment with leanback-style behavior, suitable for
+ * embedding into broader UI elements.
+ */
+public abstract class BaseLeanbackPreferenceFragment extends PreferenceFragment {
+
+ @Override
+ public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+ Bundle savedInstanceState) {
+ VerticalGridView verticalGridView = (VerticalGridView) inflater
+ .inflate(R.layout.leanback_preferences_list, parent, false);
+ verticalGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
+ verticalGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED);
+ return verticalGridView;
+ }
+}
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
new file mode 100644
index 0000000..17887e0
--- /dev/null
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.preference;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v14.preference.MultiSelectListPreference;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.preference.DialogPreference;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Checkable;
+import android.widget.TextView;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class LeanbackListPreferenceDialogFragment extends LeanbackPreferenceDialogFragment {
+
+ public static LeanbackListPreferenceDialogFragment newInstanceSingle(String key) {
+ final Bundle args = new Bundle(5);
+ args.putString(ARG_KEY, key);
+
+ final LeanbackListPreferenceDialogFragment
+ fragment = new LeanbackListPreferenceDialogFragment();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ public static LeanbackListPreferenceDialogFragment newInstanceMulti(String key) {
+ final Bundle args = new Bundle(5);
+ args.putString(ARG_KEY, key);
+
+ final LeanbackListPreferenceDialogFragment
+ fragment = new LeanbackListPreferenceDialogFragment();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final DialogPreference preference = getPreference();
+ if (!(preference instanceof ListPreference) &&
+ !(preference instanceof MultiSelectListPreference)) {
+ throw new IllegalArgumentException("Preference must be a ListPreference or " +
+ "MultiSelectListPreference");
+ }
+ }
+
+ @Override
+ public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.leanback_list_preference_fragment, container,
+ false);
+ final VerticalGridView verticalGridView =
+ (VerticalGridView) view.findViewById(android.R.id.list);
+
+ verticalGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
+ verticalGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED);
+ verticalGridView.setAdapter(onCreateAdapter());
+
+ final DialogPreference preference = getPreference();
+ final CharSequence title = preference.getDialogTitle();
+ if (!TextUtils.isEmpty(title)) {
+ final TextView titleView = (TextView) view.findViewById(R.id.decor_title);
+ titleView.setText(title);
+ }
+
+ final CharSequence message = preference.getDialogMessage();
+ if (!TextUtils.isEmpty(message)) {
+ final TextView messageView = (TextView) view.findViewById(android.R.id.message);
+ messageView.setVisibility(View.VISIBLE);
+ messageView.setText(message);
+ }
+
+ return view;
+ }
+
+ public RecyclerView.Adapter onCreateAdapter() {
+ final DialogPreference preference = getPreference();
+ if (preference instanceof MultiSelectListPreference) {
+ final MultiSelectListPreference pref = (MultiSelectListPreference) preference;
+ final CharSequence[] entries = pref.getEntries();
+ final CharSequence[] entryValues = pref.getEntryValues();
+ final Set<String> initialSelections = pref.getValues();
+ return new AdapterMulti(entries, entryValues, initialSelections);
+ } else if (preference instanceof ListPreference) {
+ final ListPreference pref = (ListPreference) preference;
+ final CharSequence[] entries = pref.getEntries();
+ final CharSequence[] entryValues = pref.getEntryValues();
+ final String initialSelection = pref.getValue();
+ return new AdapterSingle(entries, entryValues, initialSelection);
+ } else {
+ throw new IllegalStateException("Unknown preference type");
+ }
+ }
+
+ public class AdapterSingle extends RecyclerView.Adapter<ViewHolder>
+ implements ViewHolder.OnItemClickListener {
+
+ private final CharSequence[] mEntries;
+ private final CharSequence[] mEntryValues;
+ private CharSequence mSelectedValue;
+
+ public AdapterSingle(CharSequence[] entries, CharSequence[] entryValues,
+ CharSequence selectedValue) {
+ mEntries = entries;
+ mEntryValues = entryValues;
+ mSelectedValue = selectedValue;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ final View view = inflater.inflate(R.layout.leanback_list_preference_item_single,
+ parent, false);
+ return new ViewHolder(view, this);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.getWidgetView().setChecked(mEntryValues[position].equals(mSelectedValue));
+ holder.getTitleView().setText(mEntries[position]);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mEntries.length;
+ }
+
+ @Override
+ public void onItemClick(ViewHolder viewHolder) {
+ final int index = viewHolder.getAdapterPosition();
+ final CharSequence entry = mEntryValues[index];
+ mSelectedValue = entry;
+ ((ListPreference) getPreference()).setValue(entry.toString());
+ getFragmentManager().popBackStack();
+ notifyDataSetChanged();
+ }
+ }
+
+ public class AdapterMulti extends RecyclerView.Adapter<ViewHolder>
+ implements ViewHolder.OnItemClickListener {
+
+ private final CharSequence[] mEntries;
+ private final CharSequence[] mEntryValues;
+ private final Set<String> mSelections;
+
+ public AdapterMulti(CharSequence[] entries, CharSequence[] entryValues,
+ Set<String> initialSelections) {
+ mEntries = entries;
+ mEntryValues = entryValues;
+ mSelections = new HashSet<>(initialSelections);
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ final View view = inflater.inflate(R.layout.leanback_list_preference_item_multi, parent,
+ false);
+ return new ViewHolder(view, this);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.getWidgetView().setChecked(
+ mSelections.contains(mEntryValues[position].toString()));
+ holder.getTitleView().setText(mEntries[position]);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mEntries.length;
+ }
+
+ @Override
+ public void onItemClick(ViewHolder viewHolder) {
+ final int index = viewHolder.getAdapterPosition();
+ final String entry = mEntryValues[index].toString();
+ if (mSelections.contains(entry)) {
+ mSelections.remove(entry);
+ } else {
+ mSelections.add(entry);
+ }
+ ((MultiSelectListPreference) getPreference()).setValues(mSelections);
+ notifyDataSetChanged();
+ }
+ }
+
+ public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+
+ public interface OnItemClickListener {
+ void onItemClick(ViewHolder viewHolder);
+ }
+
+ private final Checkable mWidgetView;
+ private final TextView mTitleView;
+ private final ViewGroup mContainer;
+ private final OnItemClickListener mListener;
+
+ public ViewHolder(@NonNull View view, @NonNull OnItemClickListener listener) {
+ super(view);
+ mWidgetView = (Checkable) view.findViewById(R.id.button);
+ mContainer = (ViewGroup) view.findViewById(R.id.container);
+ mTitleView = (TextView) view.findViewById(android.R.id.title);
+ mContainer.setOnClickListener(this);
+ mListener = listener;
+ }
+
+ public Checkable getWidgetView() {
+ return mWidgetView;
+ }
+
+ public TextView getTitleView() {
+ return mTitleView;
+ }
+
+ public ViewGroup getContainer() {
+ return mContainer;
+ }
+
+ @Override
+ public void onClick(View v) {
+ mListener.onItemClick(this);
+ }
+ }
+}
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
new file mode 100644
index 0000000..e92ce81
--- /dev/null
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.preference;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v14.preference.MultiSelectListPreference;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.DialogPreference;
+import android.support.v7.preference.ListPreference;
+
+public class LeanbackPreferenceDialogFragment extends Fragment {
+
+ public interface TargetFragment extends DialogPreference.TargetFragment {
+
+ PreferenceFragment getPreferenceFragment();
+
+ LeanbackSettingsFragment getSettingsFragment();
+ }
+
+ public static final String ARG_KEY = "key";
+
+ private DialogPreference mPreference;
+
+ private PreferenceFragment mPreferenceFragment;
+
+ private LeanbackSettingsFragment mSettingsFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Fragment rawFragment = getParentFragment();
+ if (!(rawFragment instanceof TargetFragment)) {
+ throw new IllegalStateException("Target fragment must implement TargetFragment" +
+ " interface");
+ }
+
+ final TargetFragment fragment = (TargetFragment) rawFragment;
+
+ final String key = getArguments().getString(LeanbackListPreferenceDialogFragment.ARG_KEY);
+ mPreference = (DialogPreference) fragment.findPreference(key);
+ mPreferenceFragment = fragment.getPreferenceFragment();
+ mSettingsFragment = fragment.getSettingsFragment();
+ }
+
+ public DialogPreference getPreference() {
+ return mPreference;
+ }
+
+ public PreferenceFragment getPreferenceFragment() {
+ return mPreferenceFragment;
+ }
+
+ public LeanbackSettingsFragment getSettingsFragment() {
+ return mSettingsFragment;
+ }
+}
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java
new file mode 100644
index 0000000..73ce174
--- /dev/null
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.preference;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * This fragment provides a fully decorated leanback-style preference fragment, including a
+ * list background and header.
+ */
+public abstract class LeanbackPreferenceFragment extends BaseLeanbackPreferenceFragment {
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.leanback_preference_fragment, container, false);
+ final ViewGroup innerContainer = (ViewGroup) view.findViewById(R.id.main_frame);
+ final View innerView = super.onCreateView(inflater, innerContainer, savedInstanceState);
+ if (innerView != null) {
+ innerContainer.addView(innerView);
+ }
+ return view;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ final TextView decorTitle = (TextView) view.findViewById(R.id.decor_title);
+ decorTitle.setText(getPreferenceScreen().getTitle());
+ }
+}
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackSettingsFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackSettingsFragment.java
new file mode 100644
index 0000000..38ef3d9
--- /dev/null
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackSettingsFragment.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.preference;
+
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v14.preference.MultiSelectListPreference;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class LeanbackSettingsFragment extends Fragment
+ implements PreferenceFragment.OnPreferenceStartFragmentCallback,
+ PreferenceFragment.OnPreferenceStartScreenCallback,
+ PreferenceFragment.OnPreferenceDisplayDialogCallback {
+
+ private static final String SETTINGS_FRAGMENT_INNER_TAG =
+ "android.support.v17.preference.LeanbackSettingsFragment.INNER_FRAGMENT";
+
+ private boolean mInitialScreen;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View v = inflater.inflate(R.layout.leanback_settings_fragment, container, false);
+
+ // Trap back button presses
+ ((LeanbackSettingsRootView) v).setOnBackKeyListener(new RootViewOnKeyListener());
+
+ return v;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (savedInstanceState == null) {
+ final Fragment f = new LeanbackSettingsFragmentInner();
+ getChildFragmentManager().beginTransaction()
+ .add(R.id.settings_fragment_container, f, SETTINGS_FRAGMENT_INNER_TAG)
+ .commit();
+ getChildFragmentManager().executePendingTransactions();
+ mInitialScreen = true;
+ onPreferenceStartInitialScreen();
+ mInitialScreen = false;
+ }
+ }
+
+ @Override
+ public boolean onPreferenceDisplayDialog(PreferenceFragment caller, Preference pref) {
+ final Fragment f;
+ if (pref instanceof ListPreference) {
+ final ListPreference listPreference = (ListPreference) pref;
+ f = LeanbackListPreferenceDialogFragment.newInstanceSingle(listPreference.getKey());
+ getInnerFragment().startDialogFragment(f, caller, null);
+ } else if (pref instanceof MultiSelectListPreference) {
+ MultiSelectListPreference listPreference = (MultiSelectListPreference) pref;
+ f = LeanbackListPreferenceDialogFragment.newInstanceMulti(listPreference.getKey());
+ getInnerFragment().startDialogFragment(f, caller, null);
+ }
+ // TODO
+// else if (pref instanceof EditTextPreference) {
+//
+// }
+ else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Called to instantiate the initial {@link android.support.v14.preference.PreferenceFragment}
+ * to be shown in this fragment. Implementations are expected to call
+ * {@link #startPreferenceFragment(android.app.Fragment, java.lang.String)}.
+ */
+ public abstract void onPreferenceStartInitialScreen();
+
+ /**
+ * Displays a preference fragment to the user. This method can also be used to display
+ * list-style fragments on top of the stack of preference fragments.
+ *
+ * @param fragment Fragment instance to be added.
+ * @param tag Fragment tag
+ */
+ public void startPreferenceFragment(@NonNull Fragment fragment, @Nullable String tag) {
+ getInnerFragment().startStackedFragment(fragment, tag, !mInitialScreen);
+ }
+
+ /**
+ * Displays a fragment to the user, temporarily replacing the contents of this fragment.
+ *
+ * @param fragment Fragment instance to be added.
+ * @param tag Fragment tag
+ */
+ public void startImmersiveFragment(@NonNull Fragment fragment, @Nullable String tag) {
+ getChildFragmentManager().beginTransaction()
+ .replace(R.id.settings_fragment_container, fragment, tag)
+ .addToBackStack(null)
+ .commit();
+ }
+
+ private LeanbackSettingsFragmentInner getInnerFragment() {
+ return (LeanbackSettingsFragmentInner)
+ getChildFragmentManager().findFragmentByTag(SETTINGS_FRAGMENT_INNER_TAG);
+ }
+
+ private boolean handleBackPress() {
+ final LeanbackSettingsFragmentInner inner = getInnerFragment();
+ boolean handled = false;
+ if (inner != null && inner.isVisible()) {
+ handled = inner.handleBackPress();
+ }
+ return handled || getChildFragmentManager().popBackStackImmediate();
+ }
+
+ /**
+ * @hide
+ */
+ public static class LeanbackSettingsFragmentInner extends Fragment
+ implements LeanbackPreferenceDialogFragment.TargetFragment {
+
+ private static final String SAVESTATE_TARGET_PREF_FRAG =
+ "android.support.v17.preference.LeanbackSettingsFragment.TARGET_PREF_FRAG";
+
+ private static final String TARGET_FRAGMENT_TAG =
+ "android.support.v17.preference.LeanbackSettingsFragment.TARGET";
+
+ // Preference fragment which last launched a dialog
+ private PreferenceFragment mTargetPreferenceFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null &&
+ savedInstanceState.containsKey(SAVESTATE_TARGET_PREF_FRAG)) {
+ mTargetPreferenceFragment = (PreferenceFragment) getChildFragmentManager()
+ .getFragment(savedInstanceState, SAVESTATE_TARGET_PREF_FRAG);
+ }
+ }
+
+ @Override
+ public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.leanback_settings_fragment_stack,
+ container, false);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (mTargetPreferenceFragment != null) {
+ getChildFragmentManager().putFragment(outState, SAVESTATE_TARGET_PREF_FRAG,
+ mTargetPreferenceFragment);
+ }
+ }
+
+ public void startDialogFragment(@NonNull Fragment dialogFragment,
+ @NonNull PreferenceFragment requestingFragment, @Nullable String tag) {
+ mTargetPreferenceFragment = requestingFragment;
+ startFragment(dialogFragment, tag, true);
+ }
+
+ public void startStackedFragment(@NonNull Fragment fragment, @Nullable String tag,
+ boolean addToBackstack) {
+ fragment.setTargetFragment(findTarget(), 0);
+ startFragment(fragment, tag, addToBackstack);
+ }
+
+ private void startFragment(@NonNull Fragment fragment, @Nullable String tag,
+ boolean addToBackstack) {
+ final FragmentTransaction transaction = getChildFragmentManager().beginTransaction()
+ .add(R.id.settings_preference_stack, fragment, tag);
+ if (addToBackstack) {
+ transaction.addToBackStack(null);
+ }
+ transaction.commit();
+ }
+
+ private Fragment findTarget() {
+ Fragment target =
+ getChildFragmentManager().findFragmentByTag(TARGET_FRAGMENT_TAG);
+ if (target == null) {
+ target = new Target();
+ getChildFragmentManager().beginTransaction()
+ .add(target, TARGET_FRAGMENT_TAG)
+ .commit();
+ getChildFragmentManager().executePendingTransactions();
+ }
+ return target;
+ }
+
+ public boolean handleBackPress() {
+ return getChildFragmentManager().popBackStackImmediate();
+ }
+
+ public Preference findPreference(CharSequence key) {
+ return mTargetPreferenceFragment.findPreference(key);
+ }
+
+ public PreferenceFragment getPreferenceFragment() {
+ return mTargetPreferenceFragment;
+ }
+
+ @Override
+ public LeanbackSettingsFragment getSettingsFragment() {
+ return (LeanbackSettingsFragment) getParentFragment();
+ }
+
+ // This looks terrible, and it is. We need this because the target fragment needs to be
+ // in the same FragmentManager as the fragment targeting it.
+ /**
+ * @hide
+ */
+ public static class Target extends Fragment
+ implements PreferenceFragment.OnPreferenceStartFragmentCallback,
+ PreferenceFragment.OnPreferenceStartScreenCallback,
+ PreferenceFragment.OnPreferenceDisplayDialogCallback {
+
+ private LeanbackSettingsFragment getOuterParent() {
+ return (LeanbackSettingsFragment) getParentFragment().getParentFragment();
+ }
+
+ @Override
+ public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
+ return getOuterParent().onPreferenceStartFragment(caller, pref);
+ }
+
+ @Override
+ public boolean onPreferenceStartScreen(PreferenceFragment caller,
+ PreferenceScreen pref) {
+ return getOuterParent().onPreferenceStartScreen(caller, pref);
+ }
+
+ @Override
+ public boolean onPreferenceDisplayDialog(PreferenceFragment caller, Preference pref) {
+ return getOuterParent().onPreferenceDisplayDialog(caller, pref);
+ }
+ }
+ }
+
+ private class RootViewOnKeyListener implements View.OnKeyListener {
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ return handleBackPress();
+ } else {
+ return false;
+ }
+ }
+ }
+}
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackSettingsRootView.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackSettingsRootView.java
new file mode 100644
index 0000000..6114f13
--- /dev/null
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackSettingsRootView.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v17.preference;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.FrameLayout;
+
+/**
+ * @hide
+ */
+public class LeanbackSettingsRootView extends FrameLayout {
+
+ private OnKeyListener mOnBackKeyListener;
+
+ public LeanbackSettingsRootView(Context context) {
+ super(context);
+ }
+
+ public LeanbackSettingsRootView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LeanbackSettingsRootView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public void setOnBackKeyListener(OnKeyListener backKeyListener) {
+ mOnBackKeyListener = backKeyListener;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
+ boolean handled = false;
+ if (event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && mOnBackKeyListener != null) {
+ handled = mOnBackKeyListener.onKey(this, event.getKeyCode(), event);
+ }
+ return handled || super.dispatchKeyEvent(event);
+ }
+}
diff --git a/v4/Android.mk b/v4/Android.mk
index 6e1187a..2050725 100644
--- a/v4/Android.mk
+++ b/v4/Android.mk
@@ -184,6 +184,16 @@
# -----------------------------------------------------------------------
+# A helper sub-library that makes direct use of V23 APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v4-api23
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4-api22
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# -----------------------------------------------------------------------
+
# Here is the final static library that apps can link against.
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v4
@@ -191,8 +201,7 @@
LOCAL_AIDL_INCLUDES := frameworks/support/v4/java
LOCAL_SRC_FILES := $(call all-java-files-under, java) \
$(call all-Iaidl-files-under, java)
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4-api22
-
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4-api23
include $(BUILD_STATIC_JAVA_LIBRARY)
# API Check
diff --git a/v4/AndroidManifest.xml b/v4/AndroidManifest.xml
index 08dbb61..a21d926 100644
--- a/v4/AndroidManifest.xml
+++ b/v4/AndroidManifest.xml
@@ -15,5 +15,6 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.support.v4">
+ <uses-sdk android:minSdkVersion="4"/>
<application />
</manifest>
diff --git a/v4/api/current.txt b/v4/api/current.txt
index ec5ae3e..17a1c4e 100644
--- a/v4/api/current.txt
+++ b/v4/api/current.txt
@@ -88,15 +88,22 @@
ctor public ActivityCompat();
method public static void finishAffinity(android.app.Activity);
method public static void finishAfterTransition(android.app.Activity);
+ method public android.net.Uri getReferrer(android.app.Activity);
method public static boolean invalidateOptionsMenu(android.app.Activity);
method public static void postponeEnterTransition(android.app.Activity);
+ method public static void requestPermissions(android.app.Activity, java.lang.String[], int);
method public static void setEnterSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
method public static void setExitSharedElementCallback(android.app.Activity, android.support.v4.app.SharedElementCallback);
+ method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, java.lang.String);
method public static void startActivity(android.app.Activity, android.content.Intent, android.os.Bundle);
method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle);
method public static void startPostponedEnterTransition(android.app.Activity);
}
+ public static abstract interface ActivityCompat.OnRequestPermissionsResultCallback {
+ method public abstract void onRequestPermissionsResult(int, java.lang.String[], int[]);
+ }
+
public final class ActivityManagerCompat {
method public static boolean isLowRamDevice(android.app.ActivityManager);
}
@@ -112,6 +119,15 @@
method public void update(android.support.v4.app.ActivityOptionsCompat);
}
+ public class AppOpsManagerCompat {
+ ctor public AppOpsManagerCompat();
+ method public static int noteOp(android.content.Context, java.lang.String, int, java.lang.String);
+ method public static java.lang.String permissionToOp(java.lang.String);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_DEFAULT = 3; // 0x3
+ field public static final int MODE_IGNORED = 1; // 0x1
+ }
+
abstract class BaseFragmentActivityDonut extends android.app.Activity {
}
@@ -149,9 +165,11 @@
method public boolean getAllowReturnTransitionOverlap();
method public final android.os.Bundle getArguments();
method public final android.support.v4.app.FragmentManager getChildFragmentManager();
+ method public android.content.Context getContext();
method public java.lang.Object getEnterTransition();
method public java.lang.Object getExitTransition();
method public final android.support.v4.app.FragmentManager getFragmentManager();
+ method public final java.lang.Object getHost();
method public final int getId();
method public android.support.v4.app.LoaderManager getLoaderManager();
method public final android.support.v4.app.Fragment getParentFragment();
@@ -181,7 +199,8 @@
method public final boolean isVisible();
method public void onActivityCreated(android.os.Bundle);
method public void onActivityResult(int, int, android.content.Intent);
- method public void onAttach(android.app.Activity);
+ method public void onAttach(android.content.Context);
+ method public deprecated void onAttach(android.app.Activity);
method public void onConfigurationChanged(android.content.res.Configuration);
method public boolean onContextItemSelected(android.view.MenuItem);
method public void onCreate(android.os.Bundle);
@@ -194,12 +213,14 @@
method public void onDestroyView();
method public void onDetach();
method public void onHiddenChanged(boolean);
- method public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+ method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+ method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
method public void onLowMemory();
method public boolean onOptionsItemSelected(android.view.MenuItem);
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPause();
method public void onPrepareOptionsMenu(android.view.Menu);
+ method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method public void onResume();
method public void onSaveInstanceState(android.os.Bundle);
method public void onStart();
@@ -207,6 +228,7 @@
method public void onViewCreated(android.view.View, android.os.Bundle);
method public void onViewStateRestored(android.os.Bundle);
method public void registerForContextMenu(android.view.View);
+ method public final void requestPermissions(java.lang.String[], int);
method public void setAllowEnterTransitionOverlap(boolean);
method public void setAllowReturnTransitionOverlap(boolean);
method public void setArguments(android.os.Bundle);
@@ -224,6 +246,7 @@
method public void setSharedElementReturnTransition(java.lang.Object);
method public void setTargetFragment(android.support.v4.app.Fragment, int);
method public void setUserVisibleHint(boolean);
+ method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public void startActivity(android.content.Intent);
method public void startActivityForResult(android.content.Intent, int);
method public void unregisterForContextMenu(android.view.View);
@@ -239,7 +262,7 @@
field public static final android.os.Parcelable.Creator<android.support.v4.app.Fragment.SavedState> CREATOR;
}
- public class FragmentActivity extends android.support.v4.app.BaseFragmentActivityHoneycomb {
+ public class FragmentActivity extends android.support.v4.app.BaseFragmentActivityHoneycomb implements android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback {
ctor public FragmentActivity();
method public java.lang.Object getLastCustomNonConfigurationInstance();
method public android.support.v4.app.FragmentManager getSupportFragmentManager();
@@ -255,6 +278,68 @@
method public void supportInvalidateOptionsMenu();
method public void supportPostponeEnterTransition();
method public void supportStartPostponedEnterTransition();
+ method public final void validateRequestPermissionsRequestCode(int);
+ }
+
+ public abstract class FragmentContainer {
+ ctor public FragmentContainer();
+ method public abstract android.view.View onFindViewById(int);
+ method public abstract boolean onHasView();
+ }
+
+ public class FragmentController {
+ method public void attachHost(android.support.v4.app.Fragment);
+ method public static final android.support.v4.app.FragmentController createController(android.support.v4.app.FragmentHostCallback<?>);
+ method public void dispatchActivityCreated();
+ method public void dispatchConfigurationChanged(android.content.res.Configuration);
+ method public boolean dispatchContextItemSelected(android.view.MenuItem);
+ method public void dispatchCreate();
+ method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+ method public void dispatchDestroy();
+ method public void dispatchDestroyView();
+ method public void dispatchLowMemory();
+ method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+ method public void dispatchOptionsMenuClosed(android.view.Menu);
+ method public void dispatchPause();
+ method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+ method public void dispatchReallyStop();
+ method public void dispatchResume();
+ method public void dispatchStart();
+ method public void dispatchStop();
+ method public void doLoaderDestroy();
+ method public void doLoaderRetain();
+ method public void doLoaderStart();
+ method public void doLoaderStop(boolean);
+ method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public boolean execPendingActions();
+ method public java.util.List<android.support.v4.app.Fragment> getActiveFragments(java.util.List<android.support.v4.app.Fragment>);
+ method public int getActiveFragmentsCount();
+ method public android.support.v4.app.FragmentManager getSupportFragmentManager();
+ method public android.support.v4.app.LoaderManager getSupportLoaderManager();
+ method public void noteStateNotSaved();
+ method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+ method public void reportLoaderStart();
+ method public void restoreAllState(android.os.Parcelable, java.util.List<android.support.v4.app.Fragment>);
+ method public void restoreLoaderNonConfig(android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager>);
+ method public android.support.v4.util.SimpleArrayMap<java.lang.String, android.support.v4.app.LoaderManager> retainLoaderNonConfig();
+ method public java.util.List<android.support.v4.app.Fragment> retainNonConfig();
+ method public android.os.Parcelable saveAllState();
+ }
+
+ public abstract class FragmentHostCallback extends android.support.v4.app.FragmentContainer {
+ ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+ method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public android.view.View onFindViewById(int);
+ method public abstract E onGetHost();
+ method public android.view.LayoutInflater onGetLayoutInflater();
+ method public int onGetWindowAnimations();
+ method public boolean onHasView();
+ method public boolean onHasWindowAnimations();
+ method public void onRequestPermissionsFromFragment(android.support.v4.app.Fragment, java.lang.String[], int);
+ method public boolean onShouldSaveFragmentState(android.support.v4.app.Fragment);
+ method public boolean onShouldShowRequestPermissionRationale(java.lang.String);
+ method public void onStartActivityFromFragment(android.support.v4.app.Fragment, android.content.Intent, int);
+ method public void onSupportInvalidateOptionsMenu();
}
public abstract class FragmentManager {
@@ -857,16 +942,24 @@
public abstract class AsyncTaskLoader extends android.support.v4.content.Loader {
ctor public AsyncTaskLoader(android.content.Context);
- method public boolean cancelLoad();
+ method public void cancelLoadInBackground();
+ method public boolean isLoadInBackgroundCanceled();
method public abstract D loadInBackground();
method public void onCanceled(D);
method protected D onLoadInBackground();
method public void setUpdateThrottle(long);
}
+ public class ContentResolverCompat {
+ method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.support.v4.os.CancellationSignal);
+ }
+
public class ContextCompat {
ctor public ContextCompat();
+ method public static int checkSelfPermission(android.content.Context, java.lang.String);
method public final java.io.File getCodeCacheDir(android.content.Context);
+ method public static final int getColor(android.content.Context, int);
+ method public static final android.content.res.ColorStateList getColorStateList(android.content.Context, int);
method public static final android.graphics.drawable.Drawable getDrawable(android.content.Context, int);
method public static java.io.File[] getExternalCacheDirs(android.content.Context);
method public static java.io.File[] getExternalFilesDirs(android.content.Context, java.lang.String);
@@ -921,8 +1014,10 @@
public class Loader {
ctor public Loader(android.content.Context);
method public void abandon();
+ method public boolean cancelLoad();
method public void commitContentChanged();
method public java.lang.String dataToString(D);
+ method public void deliverCancellation();
method public void deliverResult(D);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public void forceLoad();
@@ -932,24 +1027,31 @@
method public boolean isReset();
method public boolean isStarted();
method protected void onAbandon();
+ method protected boolean onCancelLoad();
method public void onContentChanged();
method protected void onForceLoad();
method protected void onReset();
method protected void onStartLoading();
method protected void onStopLoading();
method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+ method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
method public void reset();
method public void rollbackContentChanged();
method public final void startLoading();
method public void stopLoading();
method public boolean takeContentChanged();
method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+ method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
}
public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
ctor public Loader.ForceLoadContentObserver();
}
+ public static abstract interface Loader.OnLoadCanceledListener {
+ method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+ }
+
public static abstract interface Loader.OnLoadCompleteListener {
method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
}
@@ -962,6 +1064,28 @@
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
+ public final class PermissionChecker {
+ method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
+ method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
+ method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
+ method public static int checkSelfPermission(android.content.Context, java.lang.String);
+ field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+ field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+ field public static final int PERMISSION_GRANTED = 0; // 0x0
+ }
+
+ public static abstract class PermissionChecker.PermissionResult implements java.lang.annotation.Annotation {
+ }
+
+ public class SharedPreferencesCompat {
+ ctor public SharedPreferencesCompat();
+ }
+
+ public static class SharedPreferencesCompat.EditorCompat {
+ method public void apply(android.content.SharedPreferences.Editor);
+ method public static android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
+ }
+
public abstract class WakefulBroadcastReceiver extends android.content.BroadcastReceiver {
ctor public WakefulBroadcastReceiver();
method public static boolean completeWakefulIntent(android.content.Intent);
@@ -1023,11 +1147,13 @@
public class DrawableCompat {
ctor public DrawableCompat();
+ method public static int getLayoutDirection(android.graphics.drawable.Drawable);
method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
method public static void jumpToCurrentState(android.graphics.drawable.Drawable);
method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+ method public static void setLayoutDirection(android.graphics.drawable.Drawable, int);
method public static void setTint(android.graphics.drawable.Drawable, int);
method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList);
method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
@@ -1076,6 +1202,37 @@
}
+package android.support.v4.hardware.fingerprint {
+
+ public class FingerprintManagerCompat {
+ method public void authenticate(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject, int, android.support.v4.os.CancellationSignal, android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler);
+ method public static android.support.v4.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+ method public boolean hasEnrolledFingerprints();
+ method public boolean isHardwareDetected();
+ }
+
+ public static abstract class FingerprintManagerCompat.AuthenticationCallback {
+ ctor public FingerprintManagerCompat.AuthenticationCallback();
+ method public void onAuthenticationError(int, java.lang.CharSequence);
+ method public void onAuthenticationFailed();
+ method public void onAuthenticationHelp(int, java.lang.CharSequence);
+ method public void onAuthenticationSucceeded(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult);
+ }
+
+ public static final class FingerprintManagerCompat.AuthenticationResult {
+ ctor public FingerprintManagerCompat.AuthenticationResult(android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject);
+ method public android.support.v4.hardware.fingerprint.FingerprintManagerCompat.CryptoObject getCryptoObject();
+ }
+
+ public static class FingerprintManagerCompat.CryptoObject {
+ ctor public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+ ctor public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+ method public javax.crypto.Cipher getCipher();
+ method public java.security.Signature getSignature();
+ }
+
+}
+
package android.support.v4.media {
public final class MediaDescriptionCompat implements android.os.Parcelable {
@@ -1537,12 +1694,30 @@
method public static android.os.AsyncTask<Params, Progress, Result> executeParallel(android.os.AsyncTask<Params, Progress, Result>, Params...);
}
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public java.lang.Object getCancellationSignalObject();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(android.support.v4.os.CancellationSignal.OnCancelListener);
+ method public void throwIfCanceled();
+ }
+
+ public static abstract interface CancellationSignal.OnCancelListener {
+ method public abstract void onCancel();
+ }
+
public class EnvironmentCompat {
ctor public EnvironmentCompat();
method public static java.lang.String getStorageState(java.io.File);
field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
}
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(java.lang.String);
+ }
+
public class ParcelableCompat {
ctor public ParcelableCompat();
method public static android.os.Parcelable.Creator<T> newCreator(android.support.v4.os.ParcelableCompatCreatorCallbacks<T>);
@@ -1644,8 +1819,7 @@
public class ICUCompat {
ctor public ICUCompat();
- method public static java.lang.String addLikelySubtags(java.lang.String);
- method public static java.lang.String getScript(java.lang.String);
+ method public static java.lang.String maximizeAndGetScript(java.util.Locale);
}
public abstract interface TextDirectionHeuristicCompat {
@@ -2216,6 +2390,7 @@
method public static float getZ(android.view.View);
method public static boolean hasAccessibilityDelegate(android.view.View);
method public static boolean hasNestedScrollingParent(android.view.View);
+ method public static boolean hasOverlappingRendering(android.view.View);
method public static boolean hasTransientState(android.view.View);
method public static boolean isAttachedToWindow(android.view.View);
method public static boolean isLaidOut(android.view.View);
@@ -2529,7 +2704,9 @@
method public void addAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
method public void addChild(android.view.View);
method public void addChild(android.view.View, int);
+ method public boolean canOpenPopup();
method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(java.lang.String);
+ method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(java.lang.String);
method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat findFocus(int);
method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat focusSearch(int);
method public java.util.List<android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat> getActionList();
@@ -2543,24 +2720,37 @@
method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat getCollectionItemInfo();
method public java.lang.CharSequence getContentDescription();
method public java.lang.CharSequence getError();
+ method public android.os.Bundle getExtras();
method public java.lang.Object getInfo();
+ method public int getInputType();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabelFor();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getLabeledBy();
method public int getLiveRegion();
+ method public int getMaxTextLength();
method public int getMovementGranularities();
method public java.lang.CharSequence getPackageName();
method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getParent();
method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat getRangeInfo();
method public java.lang.CharSequence getText();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalAfter();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getTraversalBefore();
method public java.lang.String getViewIdResourceName();
+ method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getWindow();
method public int getWindowId();
method public boolean isAccessibilityFocused();
method public boolean isCheckable();
method public boolean isChecked();
method public boolean isClickable();
method public boolean isContentInvalid();
+ method public boolean isDismissable();
+ method public boolean isEditable();
method public boolean isEnabled();
method public boolean isFocusable();
method public boolean isFocused();
method public boolean isLongClickable();
+ method public boolean isMultiLine();
method public boolean isPassword();
method public boolean isScrollable();
method public boolean isSelected();
@@ -2572,9 +2762,14 @@
method public boolean performAction(int);
method public boolean performAction(int, android.os.Bundle);
method public void recycle();
+ method public boolean refresh();
+ method public boolean removeAction(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat);
+ method public boolean removeChild(android.view.View);
+ method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
method public void setBoundsInParent(android.graphics.Rect);
method public void setBoundsInScreen(android.graphics.Rect);
+ method public void setCanOpenPopup(boolean);
method public void setCheckable(boolean);
method public void setChecked(boolean);
method public void setClassName(java.lang.CharSequence);
@@ -2583,24 +2778,37 @@
method public void setCollectionItemInfo(java.lang.Object);
method public void setContentDescription(java.lang.CharSequence);
method public void setContentInvalid(boolean);
+ method public void setDismissable(boolean);
+ method public void setEditable(boolean);
method public void setEnabled(boolean);
method public void setError(java.lang.CharSequence);
method public void setFocusable(boolean);
method public void setFocused(boolean);
+ method public void setInputType(int);
method public void setLabelFor(android.view.View);
method public void setLabelFor(android.view.View, int);
+ method public void setLabeledBy(android.view.View);
+ method public void setLabeledBy(android.view.View, int);
method public void setLiveRegion(int);
method public void setLongClickable(boolean);
+ method public void setMaxTextLength(int);
method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
method public void setPackageName(java.lang.CharSequence);
method public void setParent(android.view.View);
method public void setParent(android.view.View, int);
method public void setPassword(boolean);
+ method public void setRangeInfo(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat);
method public void setScrollable(boolean);
method public void setSelected(boolean);
method public void setSource(android.view.View);
method public void setSource(android.view.View, int);
method public void setText(java.lang.CharSequence);
+ method public void setTextSelection(int, int);
+ method public void setTraversalAfter(android.view.View);
+ method public void setTraversalAfter(android.view.View, int);
+ method public void setTraversalBefore(android.view.View);
+ method public void setTraversalBefore(android.view.View, int);
method public void setViewIdResourceName(java.lang.String);
method public void setVisibleToUser(boolean);
field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
@@ -2734,6 +2942,27 @@
method public void setToIndex(int);
}
+ public class AccessibilityWindowInfoCompat {
+ method public void getBoundsInScreen(android.graphics.Rect);
+ method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getChild(int);
+ method public int getChildCount();
+ method public int getId();
+ method public int getLayer();
+ method public android.support.v4.view.accessibility.AccessibilityWindowInfoCompat getParent();
+ method public android.support.v4.view.accessibility.AccessibilityNodeInfoCompat getRoot();
+ method public int getType();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActive();
+ method public boolean isFocused();
+ method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain();
+ method public static android.support.v4.view.accessibility.AccessibilityWindowInfoCompat obtain(android.support.v4.view.accessibility.AccessibilityWindowInfoCompat);
+ method public void recycle();
+ field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+ field public static final int TYPE_APPLICATION = 1; // 0x1
+ field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+ field public static final int TYPE_SYSTEM = 3; // 0x3
+ }
+
}
package android.support.v4.view.animation {
@@ -2792,6 +3021,14 @@
field public static final float RELATIVE_UNSPECIFIED = 0.0f;
}
+ public final class CompoundButtonCompat {
+ method public static android.graphics.drawable.Drawable getButtonDrawable(android.widget.CompoundButton);
+ method public static android.content.res.ColorStateList getButtonTintList(android.widget.CompoundButton);
+ method public static android.graphics.PorterDuff.Mode getButtonTintMode(android.widget.CompoundButton);
+ method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList);
+ method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode);
+ }
+
public class ContentLoadingProgressBar extends android.widget.ProgressBar {
ctor public ContentLoadingProgressBar(android.content.Context);
ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
@@ -2833,6 +3070,7 @@
method public void closeDrawer(android.view.View);
method public void closeDrawer(int);
method public void closeDrawers();
+ method public float getDrawerElevation();
method public int getDrawerLockMode(int);
method public int getDrawerLockMode(android.view.View);
method public java.lang.CharSequence getDrawerTitle(int);
@@ -2845,6 +3083,7 @@
method protected void onLayout(boolean, int, int, int, int);
method public void openDrawer(android.view.View);
method public void openDrawer(int);
+ method public void setDrawerElevation(float);
method public void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
method public void setDrawerLockMode(int);
method public void setDrawerLockMode(int, int);
@@ -2917,8 +3156,10 @@
method public void invalidateVirtualView(int);
method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
method protected abstract void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+ method public void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
method public boolean sendEventForVirtualView(int, int);
+ field public static final int HOST_ID = -1; // 0xffffffff
field public static final int INVALID_ID = -2147483648; // 0x80000000
}
@@ -2958,6 +3199,10 @@
}
public class PopupWindowCompat {
+ method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+ method public static int getWindowLayoutType(android.widget.PopupWindow);
+ method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+ method public static void setWindowLayoutType(android.widget.PopupWindow, int);
method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
}
diff --git a/v4/api21/android/support/v4/app/FragmentTransitionCompat21.java b/v4/api21/android/support/v4/app/FragmentTransitionCompat21.java
index ef41045..ddcff2e 100644
--- a/v4/api21/android/support/v4/app/FragmentTransitionCompat21.java
+++ b/v4/api21/android/support/v4/app/FragmentTransitionCompat21.java
@@ -16,14 +16,10 @@
package android.support.v4.app;
-import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Rect;
import android.transition.Transition;
-import android.transition.TransitionInflater;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
-import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -83,6 +79,19 @@
});
}
+ public static Object wrapSharedElementTransition(Object transitionObj) {
+ if (transitionObj == null) {
+ return null;
+ }
+ Transition transition = (Transition) transitionObj;
+ if (transition == null) {
+ return null;
+ }
+ TransitionSet transitionSet = new TransitionSet();
+ transitionSet.addTransition(transition);
+ return transitionSet;
+ }
+
/**
* Prepares the enter transition by adding a non-existent view to the transition's target list
* and setting it epicenter callback. By adding a non-existent view to the target list,
@@ -98,16 +107,16 @@
Object sharedElementTransitionObject, final View container,
final ViewRetriever inFragment, final View nonExistentView,
EpicenterView epicenterView, final Map<String, String> nameOverrides,
- final ArrayList<View> enteringViews, final Map<String, View> renamedViews,
- final ArrayList<View> sharedElementTargets) {
+ final ArrayList<View> enteringViews, final Map<String, View> namedViews,
+ final Map<String, View> renamedViews, final ArrayList<View> sharedElementTargets) {
if (enterTransitionObject != null || sharedElementTransitionObject != null) {
final Transition enterTransition = (Transition) enterTransitionObject;
if (enterTransition != null) {
enterTransition.addTarget(nonExistentView);
}
if (sharedElementTransitionObject != null) {
- Transition sharedElementTransition = (Transition) sharedElementTransitionObject;
- addTargets(sharedElementTransition, sharedElementTargets);
+ setSharedElementTargets(sharedElementTransitionObject, nonExistentView,
+ namedViews, sharedElementTargets);
}
if (inFragment != null) {
@@ -115,6 +124,9 @@
new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
container.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (enterTransition != null) {
+ enterTransition.removeTarget(nonExistentView);
+ }
View fragmentView = inFragment.getView();
if (fragmentView != null) {
if (!nameOverrides.isEmpty()) {
@@ -133,7 +145,6 @@
captureTransitioningViews(enteringViews, fragmentView);
enteringViews.removeAll(renamedViews.values());
enteringViews.add(nonExistentView);
- enterTransition.removeTarget(nonExistentView);
addTargets(enterTransition, enteringViews);
}
}
@@ -203,7 +214,67 @@
return transition;
}
+ /**
+ * Finds all children of the shared elements and sets the wrapping TransitionSet
+ * targets to point to those. It also limits transitions that have no targets to the
+ * specific shared elements. This allows developers to target child views of the
+ * shared elements specifically, but this doesn't happen by default.
+ */
+ public static void setSharedElementTargets(Object transitionObj,
+ View nonExistentView, Map<String, View> namedViews,
+ ArrayList<View> sharedElementTargets) {
+ TransitionSet transition = (TransitionSet) transitionObj;
+ sharedElementTargets.clear();
+ sharedElementTargets.addAll(namedViews.values());
+ final List<View> views = transition.getTargets();
+ views.clear();
+ final int count = sharedElementTargets.size();
+ for (int i = 0; i < count; i++) {
+ final View view = sharedElementTargets.get(i);
+ bfsAddViewChildren(views, view);
+ }
+ sharedElementTargets.add(nonExistentView);
+ addTargets(transition, sharedElementTargets);
+ }
+
+ /**
+ * Uses a breadth-first scheme to add startView and all of its children to views.
+ * It won't add a child if it is already in views.
+ */
+ private static void bfsAddViewChildren(final List<View> views, final View startView) {
+ final int startIndex = views.size();
+ if (containedBeforeIndex(views, startView, startIndex)) {
+ return; // This child is already in the list, so all its children are also.
+ }
+ views.add(startView);
+ for (int index = startIndex; index < views.size(); index++) {
+ final View view = views.get(index);
+ if (view instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) view;
+ final int childCount = viewGroup.getChildCount();
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
+ final View child = viewGroup.getChildAt(childIndex);
+ if (!containedBeforeIndex(views, child, startIndex)) {
+ views.add(child);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Does a linear search through views for view, limited to maxIndex.
+ */
+ private static boolean containedBeforeIndex(final List<View> views, final View view,
+ final int maxIndex) {
+ for (int i = 0; i < maxIndex; i++) {
+ if (views.get(i) == view) {
+ return true;
+ }
+ }
+ return false;
+ }
private static void setSharedElementEpicenter(Transition transition,
final EpicenterView epicenterView) {
@@ -283,7 +354,6 @@
public boolean onPreDraw() {
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
if (enterTransition != null) {
- enterTransition.removeTarget(nonExistentView);
removeTargets(enterTransition, enteringViews);
}
if (exitTransition != null) {
diff --git a/v4/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java b/v4/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java
index ce6abf3..8939fee 100644
--- a/v4/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java
+++ b/v4/api21/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatApi21.java
@@ -35,6 +35,10 @@
((AccessibilityNodeInfo) info).addAction((AccessibilityAction) action);
}
+ public static boolean removeAction(Object info, Object action) {
+ return ((AccessibilityNodeInfo) info).removeAction((AccessibilityAction) action);
+ }
+
public static Object obtainCollectionInfo(int rowCount, int columnCount,
boolean hierarchical, int selectionMode) {
return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical,
@@ -55,12 +59,24 @@
((AccessibilityNodeInfo) info).setError(error);
}
- public static void setLabelFor(Object info, View labeled) {
- ((AccessibilityNodeInfo) info).setLabelFor(labeled);
+ public static void setMaxTextLength(Object info, int max) {
+ ((AccessibilityNodeInfo) info).setMaxTextLength(max);
}
- public static void setLabelFor(Object info, View root, int virtualDescendantId) {
- ((AccessibilityNodeInfo) info).setLabelFor(root, virtualDescendantId);
+ public static int getMaxTextLength(Object info) {
+ return ((AccessibilityNodeInfo) info).getMaxTextLength();
+ }
+
+ public static Object getWindow(Object info) {
+ return ((AccessibilityNodeInfo) info).getWindow();
+ }
+
+ public static boolean removeChild(Object info, View child) {
+ return ((AccessibilityNodeInfo) info).removeChild(child);
+ }
+
+ public static boolean removeChild(Object info, View root, int virtualDescendantId) {
+ return ((AccessibilityNodeInfo) info).removeChild(root, virtualDescendantId);
}
static class CollectionItemInfo {
diff --git a/v4/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java b/v4/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java
new file mode 100644
index 0000000..c166530
--- /dev/null
+++ b/v4/api21/android/support/v4/view/accessibility/AccessibilityWindowInfoCompatApi21.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view.accessibility;
+
+import android.graphics.Rect;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+/**
+ * Api21-specific AccessibilityWindowInfo API implementation.
+ */
+class AccessibilityWindowInfoCompatApi21 {
+
+ public static Object obtain() {
+ return AccessibilityWindowInfo.obtain();
+ }
+
+ public static Object obtain(Object info) {
+ return AccessibilityWindowInfo.obtain((AccessibilityWindowInfo) info);
+
+ }
+
+ public static int getType(Object info) {
+ return ((AccessibilityWindowInfo) info).getType();
+ }
+
+ public static int getLayer(Object info) {
+ return ((AccessibilityWindowInfo) info).getLayer();
+ }
+
+ public static Object getRoot(Object info) {
+ return ((AccessibilityWindowInfo) info).getRoot();
+ }
+
+ public static Object getParent(Object info) {
+ return ((AccessibilityWindowInfo) info).getParent();
+ }
+
+ public static int getId(Object info) {
+ return ((AccessibilityWindowInfo) info).getId();
+ }
+
+ public static void getBoundsInScreen(Object info, Rect outBounds) {
+ ((AccessibilityWindowInfo) info).getBoundsInScreen(outBounds);
+ }
+
+ public static boolean isActive(Object info) {
+ return ((AccessibilityWindowInfo) info).isActive();
+ }
+
+ public static boolean isFocused(Object info) {
+ return ((AccessibilityWindowInfo) info).isFocused();
+ }
+
+ public static boolean isAccessibilityFocused(Object info) {
+ return ((AccessibilityWindowInfo) info).isAccessibilityFocused();
+ }
+
+ public static int getChildCount(Object info) {
+ return ((AccessibilityWindowInfo) info).getChildCount();
+ }
+
+ public static Object getChild(Object info, int index) {
+ return ((AccessibilityWindowInfo) info).getChild(index);
+ }
+
+ public static void recycle(Object info) {
+ ((AccessibilityWindowInfo) info).recycle();
+ }
+}
diff --git a/v4/api21/android/support/v4/widget/CompoundButtonCompatLollipop.java b/v4/api21/android/support/v4/widget/CompoundButtonCompatLollipop.java
new file mode 100644
index 0000000..17f4fdb
--- /dev/null
+++ b/v4/api21/android/support/v4/widget/CompoundButtonCompatLollipop.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.widget.CompoundButton;
+
+class CompoundButtonCompatLollipop {
+
+ static void setButtonTintList(CompoundButton button, ColorStateList tint) {
+ button.setButtonTintList(tint);
+ }
+
+ static ColorStateList getButtonTintList(CompoundButton button) {
+ return button.getButtonTintList();
+ }
+
+ static void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
+ button.setButtonTintMode(tintMode);
+ }
+
+ static PorterDuff.Mode getButtonTintMode(CompoundButton button) {
+ return button.getButtonTintMode();
+ }
+}
diff --git a/v4/api21/android/support/v4/widget/PopupWindowCompatApi21.java b/v4/api21/android/support/v4/widget/PopupWindowCompatApi21.java
new file mode 100644
index 0000000..3440f3c
--- /dev/null
+++ b/v4/api21/android/support/v4/widget/PopupWindowCompatApi21.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.util.Log;
+import android.widget.PopupWindow;
+
+import java.lang.reflect.Field;
+
+class PopupWindowCompatApi21 {
+
+ private static final String TAG = "PopupWindowCompatApi21";
+
+ private static Field sOverlapAnchorField;
+
+ static {
+ try {
+ sOverlapAnchorField = PopupWindow.class.getDeclaredField("mOverlapAnchor");
+ sOverlapAnchorField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ Log.i(TAG, "Could not fetch mOverlapAnchor field from PopupWindow", e);
+ }
+ }
+
+ static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ if (sOverlapAnchorField != null) {
+ try {
+ sOverlapAnchorField.set(popupWindow, overlapAnchor);
+ } catch (IllegalAccessException e) {
+ Log.i(TAG, "Could not set overlap anchor field in PopupWindow", e);
+ }
+ }
+ }
+
+ static boolean getOverlapAnchor(PopupWindow popupWindow) {
+ if (sOverlapAnchorField != null) {
+ try {
+ return (Boolean) sOverlapAnchorField.get(popupWindow);
+ } catch (IllegalAccessException e) {
+ Log.i(TAG, "Could not get overlap anchor field in PopupWindow", e);
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/v4/api22/android/support/v4/app/ActivityCompat22.java b/v4/api22/android/support/v4/app/ActivityCompat22.java
new file mode 100644
index 0000000..3946f1d
--- /dev/null
+++ b/v4/api22/android/support/v4/app/ActivityCompat22.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+import android.net.Uri;
+
+class ActivityCompat22 {
+ public static Uri getReferrer(Activity activity) {
+ return activity.getReferrer();
+ }
+}
diff --git a/v4/api23/android/support/v4/app/ActivityCompat23.java b/v4/api23/android/support/v4/app/ActivityCompat23.java
new file mode 100644
index 0000000..40df982
--- /dev/null
+++ b/v4/api23/android/support/v4/app/ActivityCompat23.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+
+class ActivityCompatApi23 {
+ public interface RequestPermissionsRequestCodeValidator {
+ public void validateRequestPermissionsRequestCode(int requestCode);
+ }
+
+ public static void requestPermissions(Activity activity, String[] permissions,
+ int requestCode) {
+ if (activity instanceof RequestPermissionsRequestCodeValidator) {
+ ((RequestPermissionsRequestCodeValidator) activity)
+ .validateRequestPermissionsRequestCode(requestCode);
+ }
+ activity.requestPermissions(permissions, requestCode);
+ }
+
+ public static boolean shouldShowRequestPermissionRationale(Activity activity,
+ String permission) {
+ return activity.shouldShowRequestPermissionRationale(permission);
+ }
+}
diff --git a/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java b/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
new file mode 100644
index 0000000..94034ac
--- /dev/null
+++ b/v4/api23/android/support/v4/app/AppOpsManagerCompat23.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+
+/**
+ * AppOpsManager implementations for API 23.
+ */
+public class AppOpsManagerCompat23 {
+ public static String permissionToOp(String permission) {
+ return AppOpsManager.permissionToOp(permission);
+ }
+
+ public static int noteOp(Context context, String op, int uid, String packageName) {
+ AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+ return appOpsManager.noteOp(op, uid, packageName);
+ }
+}
diff --git a/v4/api23/android/support/v4/content/ContextCompatApi23.java b/v4/api23/android/support/v4/content/ContextCompatApi23.java
new file mode 100644
index 0000000..64f1c15
--- /dev/null
+++ b/v4/api23/android/support/v4/content/ContextCompatApi23.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+
+import java.io.File;
+
+class ContextCompatApi23 {
+ public static ColorStateList getColorStateList(Context context, int id) {
+ return context.getColorStateList(id);
+ }
+
+ public static int getColor(Context context, int id) {
+ return context.getColor(id);
+ }
+}
diff --git a/v4/api23/android/support/v4/graphics/drawable/DrawableCompatApi23.java b/v4/api23/android/support/v4/graphics/drawable/DrawableCompatApi23.java
new file mode 100644
index 0000000..975d501
--- /dev/null
+++ b/v4/api23/android/support/v4/graphics/drawable/DrawableCompatApi23.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.graphics.drawable;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Implementation of drawable compatibility that can call M APIs.
+ */
+class DrawableCompatApi23 {
+ public static void setLayoutDirection(Drawable drawable, int layoutDirection) {
+ drawable.setLayoutDirection(layoutDirection);
+ }
+
+ public static int getLayoutDirection(Drawable drawable) {
+ return drawable.getLayoutDirection();
+ }
+}
diff --git a/v4/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java b/v4/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java
new file mode 100644
index 0000000..e7dec1e
--- /dev/null
+++ b/v4/api23/android/support/v4/hardware/fingerprint/FingerprintManagerCompatApi23.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.hardware.fingerprint;
+
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Handler;
+
+import java.security.Signature;
+
+import javax.crypto.Cipher;
+
+/**
+ * Actual FingerprintManagerCompat implementation for API level 23 and later.
+ */
+public final class FingerprintManagerCompatApi23 {
+
+ private static FingerprintManager getFingerprintManager(Context ctx) {
+ return ctx.getSystemService(FingerprintManager.class);
+ }
+
+ public static boolean hasEnrolledFingerprints(Context context) {
+ return getFingerprintManager(context).hasEnrolledFingerprints();
+ }
+
+ public static boolean isHardwareDetected(Context context) {
+ return getFingerprintManager(context).isHardwareDetected();
+ }
+
+ public static void authenticate(Context context, CryptoObject crypto, int flags, Object cancel,
+ AuthenticationCallback callback, Handler handler) {
+ getFingerprintManager(context).authenticate(wrapCryptoObject(crypto),
+ (android.os.CancellationSignal) cancel, flags,
+ wrapCallback(callback), handler);
+ }
+
+ private static FingerprintManager.CryptoObject wrapCryptoObject(CryptoObject cryptoObject) {
+ if (cryptoObject == null) {
+ return null;
+ } else if (cryptoObject.getCipher() != null) {
+ return new FingerprintManager.CryptoObject(cryptoObject.getCipher());
+ } else {
+ return new FingerprintManager.CryptoObject(cryptoObject.getSignature());
+ }
+ }
+
+ private static CryptoObject unwrapCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
+ if (cryptoObject == null) {
+ return null;
+ } else if (cryptoObject.getCipher() != null) {
+ return new CryptoObject(cryptoObject.getCipher());
+ } else {
+ return new CryptoObject(cryptoObject.getSignature());
+ }
+ }
+
+ private static FingerprintManager.AuthenticationCallback wrapCallback(
+ final AuthenticationCallback callback) {
+ return new FingerprintManager.AuthenticationCallback() {
+ @Override
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ callback.onAuthenticationError(errMsgId, errString);
+ }
+
+ @Override
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ callback.onAuthenticationHelp(helpMsgId, helpString);
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
+ callback.onAuthenticationSucceeded(new AuthenticationResultInternal(
+ unwrapCryptoObject(result.getCryptoObject())));
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ callback.onAuthenticationFailed();
+ }
+ };
+ }
+
+ public static class CryptoObject {
+
+ private final Signature mSignature;
+ private final Cipher mCipher;
+
+ public CryptoObject(Signature signature) {
+ mSignature = signature;
+ mCipher = null;
+ }
+
+ public CryptoObject(Cipher cipher) {
+ mCipher = cipher;
+ mSignature = null;
+ }
+
+ public Signature getSignature() { return mSignature; }
+ public Cipher getCipher() { return mCipher; }
+ }
+
+ public static final class AuthenticationResultInternal {
+ private CryptoObject mCryptoObject;
+
+ public AuthenticationResultInternal(CryptoObject crypto) {
+ mCryptoObject = crypto;
+ }
+
+ public CryptoObject getCryptoObject() { return mCryptoObject; }
+ }
+
+ public static abstract class AuthenticationCallback {
+
+ public void onAuthenticationError(int errMsgId, CharSequence errString) { }
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { }
+ public void onAuthenticationSucceeded(AuthenticationResultInternal result) { }
+ public void onAuthenticationFailed() { }
+ }
+}
diff --git a/v4/api23/android/support/v4/text/ICUCompatApi23.java b/v4/api23/android/support/v4/text/ICUCompatApi23.java
new file mode 100644
index 0000000..f013522
--- /dev/null
+++ b/v4/api23/android/support/v4/text/ICUCompatApi23.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.text;
+
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+public class ICUCompatApi23 {
+
+ private static final String TAG = "ICUCompatIcs";
+
+ private static Method sAddLikelySubtagsMethod;
+
+ static {
+ try {
+ // This class should always exist on API-23 since it's CTS tested.
+ final Class<?> clazz = Class.forName("libcore.icu.ICU");
+ sAddLikelySubtagsMethod = clazz.getMethod("addLikelySubtags",
+ new Class[]{ Locale.class });
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+
+ public static String maximizeAndGetScript(Locale locale) {
+ try {
+ final Object[] args = new Object[] { locale };
+ return ((Locale) sAddLikelySubtagsMethod.invoke(null, args)).getScript();
+ } catch (InvocationTargetException e) {
+ Log.w(TAG, e);
+ } catch (IllegalAccessException e) {
+ Log.w(TAG, e);
+ }
+
+ return locale.getScript();
+ }
+}
diff --git a/v4/api23/android/support/v4/widget/CompoundButtonCompatApi23.java b/v4/api23/android/support/v4/widget/CompoundButtonCompatApi23.java
new file mode 100644
index 0000000..0c55bbc
--- /dev/null
+++ b/v4/api23/android/support/v4/widget/CompoundButtonCompatApi23.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+import android.widget.CompoundButton;
+
+class CompoundButtonCompatApi23 {
+
+ static Drawable getButtonDrawable(CompoundButton button) {
+ return button.getButtonDrawable();
+ }
+}
diff --git a/v4/api23/android/support/v4/widget/PopupWindowCompatApi23.java b/v4/api23/android/support/v4/widget/PopupWindowCompatApi23.java
new file mode 100644
index 0000000..96bf8d9
--- /dev/null
+++ b/v4/api23/android/support/v4/widget/PopupWindowCompatApi23.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.widget.PopupWindow;
+
+class PopupWindowCompatApi23 {
+
+ static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ popupWindow.setOverlapAnchor(overlapAnchor);
+ }
+
+ static boolean getOverlapAnchor(PopupWindow popupWindow) {
+ return popupWindow.getOverlapAnchor();
+ }
+
+ static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ popupWindow.setWindowLayoutType(layoutType);
+ }
+
+ static int getWindowLayoutType(PopupWindow popupWindow) {
+ return popupWindow.getWindowLayoutType();
+ }
+
+}
diff --git a/v4/build.gradle b/v4/build.gradle
index e64c5ad..a056973 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -27,9 +27,10 @@
def jbMr1SS = createApiSourceset('jellybeanmr1', 'jellybean-mr1', '17', jbSS)
def jbMr2SS = createApiSourceset('jellybeanmr2', 'jellybean-mr2', '18', jbMr1SS)
def kitkatSS = createApiSourceset('kitkat', 'kitkat', '19', jbMr2SS)
-def api20SS = createApiSourceset('api20', 'api20', '20', kitkatSS)
-def api21SS = createApiSourceset('api21', 'api21', '21', api20SS)
-def api22SS = createApiSourceset('api22', 'api22', 'current', api21SS)
+def api20SS = createApiSourceset('api20', 'api20', '20', kitkatSS)
+def api21SS = createApiSourceset('api21', 'api21', '21', api20SS)
+def api22SS = createApiSourceset('api22', 'api22', '22', api21SS)
+def api23SS = createApiSourceset('api23', 'api23', 'current', api22SS)
def createApiSourceset(String name, String folder, String apiLevel, SourceSet previousSource) {
diff --git a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
index e3672c8..9293520 100644
--- a/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
+++ b/v4/donut/android/support/v4/graphics/drawable/DrawableWrapperDonut.java
@@ -215,6 +215,9 @@
mColorFilterSet = true;
return true;
}
+ } else {
+ mColorFilterSet = false;
+ clearColorFilter();
}
return false;
}
diff --git a/v4/donut/android/support/v4/widget/CompoundButtonCompatDonut.java b/v4/donut/android/support/v4/widget/CompoundButtonCompatDonut.java
new file mode 100644
index 0000000..af9e19f
--- /dev/null
+++ b/v4/donut/android/support/v4/widget/CompoundButtonCompatDonut.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.widget.CompoundButton;
+
+import java.lang.reflect.Field;
+
+class CompoundButtonCompatDonut {
+
+ private static final String TAG = "CompoundButtonCompatDonut";
+
+ private static Field sButtonDrawableField;
+ private static boolean sButtonDrawableFieldFetched;
+
+ static void setButtonTintList(CompoundButton button, ColorStateList tint) {
+ if (button instanceof TintableCompoundButton) {
+ ((TintableCompoundButton) button).setSupportButtonTintList(tint);
+ }
+ }
+
+ static ColorStateList getButtonTintList(CompoundButton button) {
+ if (button instanceof TintableCompoundButton) {
+ return((TintableCompoundButton) button).getSupportButtonTintList();
+ }
+ return null;
+ }
+
+ static void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
+ if (button instanceof TintableCompoundButton) {
+ ((TintableCompoundButton) button).setSupportButtonTintMode(tintMode);
+ }
+ }
+
+ static PorterDuff.Mode getButtonTintMode(CompoundButton button) {
+ if (button instanceof TintableCompoundButton) {
+ return ((TintableCompoundButton) button).getSupportButtonTintMode();
+ }
+ return null;
+ }
+
+ static Drawable getButtonDrawable(CompoundButton button) {
+ if (!sButtonDrawableFieldFetched) {
+ try {
+ sButtonDrawableField = CompoundButton.class.getDeclaredField("mButtonDrawable");
+ sButtonDrawableField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ Log.i(TAG, "Failed to retrieve mButtonDrawable field", e);
+ }
+ sButtonDrawableFieldFetched = true;
+ }
+
+ if (sButtonDrawableField != null) {
+ try {
+ return (Drawable) sButtonDrawableField.get(button);
+ } catch (IllegalAccessException e) {
+ Log.i(TAG, "Failed to get button drawable via reflection", e);
+ sButtonDrawableField = null;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/v4/donut/android/support/v4/widget/TintableCompoundButton.java b/v4/donut/android/support/v4/widget/TintableCompoundButton.java
new file mode 100644
index 0000000..6bcfa30
--- /dev/null
+++ b/v4/donut/android/support/v4/widget/TintableCompoundButton.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+
+/**
+ * Interface which allows a {@link android.widget.CompoundButton} to receive tinting
+ * calls from {@code CompoundButtonCompat} when running on API v20 devices or lower.
+ */
+public interface TintableCompoundButton {
+
+ /**
+ * Applies a tint to the button drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+ * <p>
+ * Subsequent calls to
+ * {@link android.widget.CompoundButton#setButtonDrawable(Drawable) setButtonDrawable(Drawable)}
+ * should automatically mutate the drawable and apply the specified tint and tint mode.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ */
+ public void setSupportButtonTintList(@Nullable ColorStateList tint);
+
+ /**
+ * Returns the tint applied to the button drawable
+ *
+ * @see #setSupportButtonTintList(ColorStateList)
+ */
+ @Nullable
+ public ColorStateList getSupportButtonTintList();
+
+ /**
+ * Specifies the blending mode which should be used to apply the tint specified by
+ * {@link #setSupportButtonTintList(ColorStateList)} to the button drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_IN}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @see #getSupportButtonTintMode()
+ * @see DrawableCompat#setTintMode(Drawable, PorterDuff.Mode)
+ */
+ public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode);
+
+ /**
+ * Returns the blending mode used to apply the tint to the button drawable
+ *
+ * @see #setSupportButtonTintMode(PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getSupportButtonTintMode();
+}
diff --git a/v4/gingerbread/android/support/v4/content/EditorCompatGingerbread.java b/v4/gingerbread/android/support/v4/content/EditorCompatGingerbread.java
new file mode 100644
index 0000000..394964d
--- /dev/null
+++ b/v4/gingerbread/android/support/v4/content/EditorCompatGingerbread.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.content;
+
+import android.content.SharedPreferences;
+import android.support.annotation.NonNull;
+
+class EditorCompatGingerbread {
+ public static void apply(@NonNull SharedPreferences.Editor editor) {
+ try {
+ editor.apply();
+ } catch (AbstractMethodError unused) {
+ // The app injected its own pre-Gingerbread
+ // SharedPreferences.Editor implementation without
+ // an apply method.
+ editor.commit();
+ }
+ }
+}
diff --git a/v4/gingerbread/android/support/v4/widget/PopupWindowCompatGingerbread.java b/v4/gingerbread/android/support/v4/widget/PopupWindowCompatGingerbread.java
new file mode 100644
index 0000000..b87db30
--- /dev/null
+++ b/v4/gingerbread/android/support/v4/widget/PopupWindowCompatGingerbread.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.widget;
+
+import android.widget.PopupWindow;
+
+import java.lang.reflect.Method;
+
+/**
+ * Implementation of PopupWindow compatibility that can call Gingerbread APIs.
+ */
+class PopupWindowCompatGingerbread {
+
+ private static Method sSetWindowLayoutTypeMethod;
+ private static boolean sSetWindowLayoutTypeMethodAttempted;
+ private static Method sGetWindowLayoutTypeMethod;
+ private static boolean sGetWindowLayoutTypeMethodAttempted;
+
+ static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ if (!sSetWindowLayoutTypeMethodAttempted) {
+ try {
+ sSetWindowLayoutTypeMethod = PopupWindow.class.getDeclaredMethod(
+ "setWindowLayoutType", int.class);
+ sSetWindowLayoutTypeMethod.setAccessible(true);
+ } catch (Exception e) {
+ // Reflection method fetch failed. Oh well.
+ }
+ sSetWindowLayoutTypeMethodAttempted = true;
+ }
+
+ if (sSetWindowLayoutTypeMethod != null) {
+ try {
+ sSetWindowLayoutTypeMethod.invoke(popupWindow, layoutType);
+ } catch (Exception e) {
+ // Reflection call failed. Oh well.
+ }
+ }
+ }
+
+ static int getWindowLayoutType(PopupWindow popupWindow) {
+ if (!sGetWindowLayoutTypeMethodAttempted) {
+ try {
+ sGetWindowLayoutTypeMethod = PopupWindow.class.getDeclaredMethod(
+ "getWindowLayoutType");
+ sGetWindowLayoutTypeMethod.setAccessible(true);
+ } catch (Exception e) {
+ // Reflection method fetch failed. Oh well.
+ }
+ sGetWindowLayoutTypeMethodAttempted = true;
+ }
+
+ if (sGetWindowLayoutTypeMethod != null) {
+ try {
+ return (Integer) sGetWindowLayoutTypeMethod.invoke(popupWindow);
+ } catch (Exception e) {
+ // Reflection call failed. Oh well.
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/v4/ics/android/support/v4/text/ICUCompatIcs.java b/v4/ics/android/support/v4/text/ICUCompatIcs.java
index 7dc5d3c..dfb9e7e 100644
--- a/v4/ics/android/support/v4/text/ICUCompatIcs.java
+++ b/v4/ics/android/support/v4/text/ICUCompatIcs.java
@@ -20,6 +20,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Locale;
class ICUCompatIcs {
@@ -38,15 +39,27 @@
new Class[]{ String.class });
}
} catch (Exception e) {
+ sGetScriptMethod = null;
+ sAddLikelySubtagsMethod = null;
+
// Nothing we can do here, we just log the exception
Log.w(TAG, e);
}
}
- public static String getScript(String locale) {
+ public static String maximizeAndGetScript(Locale locale) {
+ final String localeWithSubtags = addLikelySubtags(locale);
+ if (localeWithSubtags != null) {
+ return getScript(localeWithSubtags);
+ }
+
+ return null;
+ }
+
+ private static String getScript(String localeStr) {
try {
if (sGetScriptMethod != null) {
- final Object[] args = new Object[] { locale };
+ final Object[] args = new Object[] { localeStr };
return (String) sGetScriptMethod.invoke(null, args);
}
} catch (IllegalAccessException e) {
@@ -60,10 +73,11 @@
return null;
}
- public static String addLikelySubtags(String locale) {
+ private static String addLikelySubtags(Locale locale) {
+ final String localeStr = locale.toString();
try {
if (sAddLikelySubtagsMethod != null) {
- final Object[] args = new Object[] { locale };
+ final Object[] args = new Object[] { localeStr };
return (String) sAddLikelySubtagsMethod.invoke(null, args);
}
} catch (IllegalAccessException e) {
@@ -74,6 +88,7 @@
// Nothing we can do here, we just log the exception
Log.w(TAG, e);
}
- return locale;
+
+ return localeStr;
}
}
diff --git a/v4/java/android/support/v4/app/ActivityCompat.java b/v4/java/android/support/v4/app/ActivityCompat.java
index 8d8bf04..58cc199 100644
--- a/v4/java/android/support/v4/app/ActivityCompat.java
+++ b/v4/java/android/support/v4/app/ActivityCompat.java
@@ -19,15 +19,21 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.RectF;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.view.View;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -36,6 +42,30 @@
* introduced after API level 4 in a backwards compatible fashion.
*/
public class ActivityCompat extends ContextCompat {
+
+ /**
+ * This interface is the contract for receiving the results for permission requests.
+ */
+ public interface OnRequestPermissionsResultCallback {
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(android.app.Activity,
+ * String[], int)}
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(
+ * android.app.Activity, String[], int)}
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(android.app.Activity, String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults);
+ }
+
/**
* Invalidate the activity's options menu, if able.
*
@@ -163,6 +193,27 @@
}
/**
+ * Backwards compatible implementation of {@link android.app.Activity#getReferrer()
+ * Activity.getReferrer}. Uses the platform's implementation if available, otherwise
+ * only falls back to digging any explicitly specified referrer from the activity's intent.
+ */
+ public Uri getReferrer(Activity activity) {
+ if (Build.VERSION.SDK_INT >= 22) {
+ return ActivityCompat22.getReferrer(activity);
+ }
+ Intent intent = activity.getIntent();
+ Uri referrer = intent.getParcelableExtra("android.intent.extra.REFERRER");
+ if (referrer != null) {
+ return referrer;
+ }
+ String referrerName = intent.getStringExtra("android.intent.extra.REFERRER_NAME");
+ if (referrerName != null) {
+ return Uri.parse(referrerName);
+ }
+ return null;
+ }
+
+ /**
* When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
* android.view.View, String)} was used to start an Activity, <var>callback</var>
* will be called to handle shared elements on the <i>launched</i> Activity. This requires
@@ -205,6 +256,103 @@
}
}
+ /**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback reporting whether the
+ * permissions were granted or not. Your activity has to implement {@link
+ * android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback}
+ * and the results of permission requests will be delivered to its {@link
+ * android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(
+ * int, String[], int[])} method.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to your onRequestPermissionsResult(
+ * int, String[], int[]).
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * #checkSelfPermission(android.content.Context, String)}.
+ * </p>
+ *
+ * @param activity The target activity.
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
+ * int, String[], int[])}.
+ *
+ * @see #checkSelfPermission(android.content.Context, String)
+ * @see #shouldShowRequestPermissionRationale(android.app.Activity, String)
+ */
+ public static void requestPermissions(final @NonNull Activity activity,
+ final @NonNull String[] permissions, final int requestCode) {
+ // TODO: Change to comparison against API 23 once we have it defined.
+ if (Build.VERSION.CODENAME.equals("MNC") || Build.VERSION.SDK_INT > 22) {
+ ActivityCompatApi23.requestPermissions(activity, permissions, requestCode);
+ } else if (activity instanceof OnRequestPermissionsResultCallback) {
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ final int[] grantResults = new int[permissions.length];
+ Arrays.fill(grantResults, PackageManager.PERMISSION_GRANTED);
+ ((OnRequestPermissionsResultCallback) activity).onRequestPermissionsResult(
+ requestCode, permissions, grantResults);
+ }
+ });
+ }
+ }
+
+ /**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from granting this permission.
+ * <p>
+ * For example, if you write a camera app, requesting the camera permission
+ * would be expected by the user and no rationale for why it is requested is
+ * needed. If however, the app needs location for tagging photos then a non-tech
+ * savvy user may wonder how location is related to taking photos. In this case
+ * you may choose to show UI with rationale of requesting this permission.
+ * </p>
+ *
+ * @param activity The target activity.
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @see #checkSelfPermission(android.content.Context, String)
+ * @see #requestPermissions(android.app.Activity, String[], int)
+ */
+ public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
+ @NonNull String permission) {
+ // TODO: Change to comparison against API 23 once we have it defined.
+ if (Build.VERSION.CODENAME.equals("MNC") || Build.VERSION.SDK_INT > 22) {
+ return ActivityCompatApi23.shouldShowRequestPermissionRationale(activity, permission);
+ }
+ return false;
+ }
+
private static ActivityCompat21.SharedElementCallback21 createCallback(
SharedElementCallback callback) {
ActivityCompat21.SharedElementCallback21 newCallback = null;
diff --git a/v4/java/android/support/v4/app/AppOpsManagerCompat.java b/v4/java/android/support/v4/app/AppOpsManagerCompat.java
new file mode 100644
index 0000000..49d4940
--- /dev/null
+++ b/v4/java/android/support/v4/app/AppOpsManagerCompat.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+/**
+ * Helper for accessing features in android.app.AppOpsManager
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class AppOpsManagerCompat {
+
+ /**
+ * Result from {@link #noteOp}: the given caller is allowed to
+ * perform the given operation.
+ */
+ public static final int MODE_ALLOWED = 0;
+
+ /**
+ * Result from {@link #noteOp}: the given caller is not allowed to perform
+ * the given operation, and this attempt should <em>silently fail</em> (it
+ * should not cause the app to crash).
+ */
+ public static final int MODE_IGNORED = 1;
+
+ /**
+ * Result from {@link #noteOp}: the given caller should use its default
+ * security check. This mode is not normally used; it should only be used
+ * with appop permissions, and callers must explicitly check for it and
+ * deal with it.
+ */
+ public static final int MODE_DEFAULT = 3;
+
+ private static class AppOpsManagerImpl {
+ public String permissionToOp(String permission) {
+ return null;
+ }
+
+ public int noteOp(Context context, String op, int uid, String packageName) {
+ return MODE_IGNORED;
+ }
+ }
+
+ private static class AppOpsManager23 extends AppOpsManagerImpl {
+ @Override
+ public String permissionToOp(String permission) {
+ return AppOpsManagerCompat23.permissionToOp(permission);
+ }
+
+ @Override
+ public int noteOp(Context context, String op, int uid, String packageName) {
+ return AppOpsManagerCompat23.noteOp(context, op, uid, packageName);
+ }
+ }
+
+ private static final AppOpsManagerImpl IMPL;
+ static {
+ // TODO: Change to comparison against API 23 once we have it defined.
+ if (Build.VERSION.CODENAME.equals("MNC") || Build.VERSION.SDK_INT > 22) {
+ IMPL = new AppOpsManager23();
+ } else {
+ IMPL = new AppOpsManagerImpl();
+ }
+ }
+
+ /**
+ * Gets the app op name associated with a given permission.
+ *
+ * @param permission The permission.
+ * @return The app op associated with the permission or null.
+ */
+ public static String permissionToOp(@NonNull String permission) {
+ return IMPL.permissionToOp(permission);
+ }
+
+ /**
+ * Make note of an application performing an operation. Note that you must pass
+ * in both the uid and name of the application to be checked; this function will verify
+ * that these two match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for this app will be updated to
+ * the current time.
+ * @param context Your context.
+ * @param op The operation to note. One of the OPSTR_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
+ public static int noteOp(@NonNull Context context, String op, int uid, String packageName) {
+ return IMPL.noteOp(context, op, uid, packageName);
+ }
+}
diff --git a/v4/java/android/support/v4/app/BackStackRecord.java b/v4/java/android/support/v4/app/BackStackRecord.java
index 25f3ebf..f2eaad5 100644
--- a/v4/java/android/support/v4/app/BackStackRecord.java
+++ b/v4/java/android/support/v4/app/BackStackRecord.java
@@ -16,13 +16,11 @@
package android.support.v4.app;
-import android.graphics.Rect;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.v4.util.LogWriter;
-import android.support.v4.util.Pair;
import android.support.v4.util.ArrayMap;
+import android.support.v4.util.LogWriter;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -33,7 +31,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
final class BackStackState implements Parcelable {
final int[] mOps;
@@ -48,7 +45,7 @@
final ArrayList<String> mSharedElementSourceNames;
final ArrayList<String> mSharedElementTargetNames;
- public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
+ public BackStackState(BackStackRecord bse) {
int numRemoved = 0;
BackStackRecord.Op op = bse.mHead;
while (op != null) {
@@ -371,14 +368,14 @@
public CharSequence getBreadCrumbTitle() {
if (mBreadCrumbTitleRes != 0) {
- return mManager.mActivity.getText(mBreadCrumbTitleRes);
+ return mManager.mHost.getContext().getText(mBreadCrumbTitleRes);
}
return mBreadCrumbTitleText;
}
public CharSequence getBreadCrumbShortTitle() {
if (mBreadCrumbShortTitleRes != 0) {
- return mManager.mActivity.getText(mBreadCrumbShortTitleRes);
+ return mManager.mHost.getContext().getText(mBreadCrumbShortTitleRes);
}
return mBreadCrumbShortTitleText;
}
@@ -774,7 +771,7 @@
*/
private void calculateFragments(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments) {
- if (!mManager.mContainer.hasView()) {
+ if (!mManager.mContainer.onHasView()) {
return; // nothing to see, so no transitions
}
Op op = mHead;
@@ -832,7 +829,7 @@
*/
public void calculateBackFragments(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments) {
- if (!mManager.mContainer.hasView()) {
+ if (!mManager.mContainer.onHasView()) {
return; // nothing to see, so no transitions
}
Op op = mHead;
@@ -1023,7 +1020,7 @@
// Adding a non-existent target view makes sure that the transitions don't target
// any views by default. They'll only target the views we tell add. If we don't
// add any, then no views will be targeted.
- state.nonExistentView = new View(mManager.mActivity);
+ state.nonExistentView = new View(mManager.mHost.getContext());
boolean anyTransitionStarted = false;
// Go over all leaving fragments.
@@ -1073,7 +1070,7 @@
if (inFragment == null || outFragment == null) {
return null;
}
- return FragmentTransitionCompat21.cloneTransition(isBack ?
+ return FragmentTransitionCompat21.wrapSharedElementTransition(isBack ?
outFragment.getSharedElementReturnTransition() :
inFragment.getSharedElementEnterTransition());
}
@@ -1131,7 +1128,7 @@
*/
private boolean configureTransitions(int containerId, TransitionState state, boolean isBack,
SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
- ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
+ ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.onFindViewById(containerId);
if (sceneRoot == null) {
return false;
}
@@ -1142,27 +1139,31 @@
Object sharedElementTransition = getSharedElementTransition(inFragment, outFragment,
isBack);
Object exitTransition = getExitTransition(outFragment, isBack);
- if (enterTransition == null && sharedElementTransition == null &&
- exitTransition == null) {
- return false; // no transitions!
- }
ArrayMap<String, View> namedViews = null;
ArrayList<View> sharedElementTargets = new ArrayList<View>();
if (sharedElementTransition != null) {
namedViews = remapSharedElements(state, outFragment, isBack);
- sharedElementTargets.add(state.nonExistentView);
- sharedElementTargets.addAll(namedViews.values());
-
- // Notify the start of the transition.
- SharedElementCallback callback = isBack ?
- outFragment.mEnterTransitionCallback :
- inFragment.mEnterTransitionCallback;
- if (callback != null) {
- ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
- ArrayList<View> views = new ArrayList<View>(namedViews.values());
- callback.onSharedElementStart(names, views, null);
+ if (namedViews.isEmpty()) {
+ sharedElementTransition = null;
+ namedViews = null;
+ } else {
+ // Notify the start of the transition.
+ SharedElementCallback callback = isBack ?
+ outFragment.mEnterTransitionCallback :
+ inFragment.mEnterTransitionCallback;
+ if (callback != null) {
+ ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+ ArrayList<View> views = new ArrayList<View>(namedViews.values());
+ callback.onSharedElementStart(names, views, null);
+ }
+ prepareSharedElementTransition(state, sceneRoot, sharedElementTransition,
+ inFragment, outFragment, isBack, sharedElementTargets);
}
}
+ if (enterTransition == null && sharedElementTransition == null &&
+ exitTransition == null) {
+ return false; // no transitions!
+ }
ArrayList<View> exitingViews = new ArrayList<View>();
exitTransition = captureExitingViews(exitTransition, outFragment, exitingViews,
@@ -1190,16 +1191,14 @@
}
};
- if (sharedElementTransition != null) {
- prepareSharedElementTransition(state, sceneRoot, sharedElementTransition,
- inFragment, outFragment, isBack, sharedElementTargets);
- }
-
ArrayList<View> enteringViews = new ArrayList<View>();
ArrayMap<String, View> renamedViews = new ArrayMap<String, View>();
- boolean allowOverlap = isBack ? inFragment.getAllowReturnTransitionOverlap() :
- inFragment.getAllowEnterTransitionOverlap();
+ boolean allowOverlap = true;
+ if (inFragment != null) {
+ allowOverlap = isBack ? inFragment.getAllowReturnTransitionOverlap() :
+ inFragment.getAllowEnterTransitionOverlap();
+ }
Object transition = FragmentTransitionCompat21.mergeTransitions(enterTransition,
exitTransition, sharedElementTransition, allowOverlap);
@@ -1207,7 +1206,7 @@
FragmentTransitionCompat21.addTransitionTargets(enterTransition,
sharedElementTransition, sceneRoot, viewRetriever, state.nonExistentView,
state.enteringEpicenterView, state.nameOverrides, enteringViews,
- renamedViews, sharedElementTargets);
+ namedViews, renamedViews, sharedElementTargets);
excludeHiddenFragmentsAfterEnter(sceneRoot, state, containerId, transition);
// We want to exclude hidden views later, so we need a non-null list in the
@@ -1243,10 +1242,8 @@
ArrayMap<String, View> namedViews = mapSharedElementsIn(
state, isBack, inFragment);
- sharedElementTargets.add(state.nonExistentView);
- sharedElementTargets.addAll(namedViews.values());
- FragmentTransitionCompat21.addTargets(sharedElementTransition,
- sharedElementTargets);
+ FragmentTransitionCompat21.setSharedElementTargets(sharedElementTransition,
+ state.nonExistentView, namedViews, sharedElementTargets);
setEpicenterIn(namedViews, state);
@@ -1392,7 +1389,7 @@
private static void setNameOverride(ArrayMap<String, String> overrides,
String source, String target) {
- if (source != null && target != null && !source.equals(target)) {
+ if (source != null && target != null) {
for (int index = 0; index < overrides.size(); index++) {
if (source.equals(overrides.valueAt(index))) {
overrides.setValueAt(index, target);
diff --git a/v4/java/android/support/v4/app/DialogFragment.java b/v4/java/android/support/v4/app/DialogFragment.java
index 343c145..fa7ad7b 100644
--- a/v4/java/android/support/v4/app/DialogFragment.java
+++ b/v4/java/android/support/v4/app/DialogFragment.java
@@ -306,23 +306,30 @@
}
mDialog = onCreateDialog(savedInstanceState);
- switch (mStyle) {
- case STYLE_NO_INPUT:
- mDialog.getWindow().addFlags(
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
- // fall through...
- case STYLE_NO_FRAME:
- case STYLE_NO_TITLE:
- mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- }
+
if (mDialog != null) {
+ setupDialog(mDialog, mStyle);
+
return (LayoutInflater) mDialog.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
}
- return (LayoutInflater) mActivity.getSystemService(
+ return (LayoutInflater) mHost.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
}
+
+ /** @hide */
+ public void setupDialog(Dialog dialog, int style) {
+ switch (style) {
+ case STYLE_NO_INPUT:
+ dialog.getWindow().addFlags(
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ // fall through...
+ case STYLE_NO_FRAME:
+ case STYLE_NO_TITLE:
+ dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ }
+ }
/**
* Override to build your own custom Dialog container. This is typically
diff --git a/v4/java/android/support/v4/app/Fragment.java b/v4/java/android/support/v4/app/Fragment.java
index eb6ab0d..d61f900 100644
--- a/v4/java/android/support/v4/app/Fragment.java
+++ b/v4/java/android/support/v4/app/Fragment.java
@@ -22,11 +22,10 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.util.SimpleArrayMap;
@@ -89,20 +88,21 @@
mArguments = in.readBundle();
mSavedFragmentState = in.readBundle();
}
-
- public Fragment instantiate(FragmentActivity activity, Fragment parent) {
+
+ public Fragment instantiate(FragmentHostCallback host, Fragment parent) {
if (mInstance != null) {
return mInstance;
}
-
+
+ final Context context = host.getContext();
if (mArguments != null) {
- mArguments.setClassLoader(activity.getClassLoader());
+ mArguments.setClassLoader(context.getClassLoader());
}
-
- mInstance = Fragment.instantiate(activity, mClassName, mArguments);
-
+
+ mInstance = Fragment.instantiate(context, mClassName, mArguments);
+
if (mSavedFragmentState != null) {
- mSavedFragmentState.setClassLoader(activity.getClassLoader());
+ mSavedFragmentState.setClassLoader(context.getClassLoader());
mInstance.mSavedFragmentState = mSavedFragmentState;
}
mInstance.setIndex(mIndex, parent);
@@ -113,14 +113,14 @@
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
mInstance.mDetached = mDetached;
- mInstance.mFragmentManager = activity.mFragments;
+ mInstance.mFragmentManager = host.mFragmentManager;
if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
"Instantiated fragment " + mInstance);
return mInstance;
}
-
+
public int describeContents() {
return 0;
}
@@ -228,17 +228,17 @@
// True if this fragment has been restored from previously saved state.
boolean mRestored;
-
+
// Number of active back stack entries this fragment is in.
int mBackStackNesting;
-
+
// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
FragmentManagerImpl mFragmentManager;
- // Activity this fragment is attached to.
- FragmentActivity mActivity;
+ // Host this fragment is attached to.
+ FragmentHostCallback mHost;
// Private fragment manager for child fragments inside of this one.
FragmentManagerImpl mChildFragmentManager;
@@ -348,10 +348,12 @@
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
+ @Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in, null);
}
+ @Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
@@ -606,22 +608,39 @@
}
/**
- * Return the Activity this fragment is currently associated with.
+ * Return the {@link Context} this fragment is currently associated with.
+ */
+ public Context getContext() {
+ return mHost == null ? null : mHost.getContext();
+ }
+
+ /**
+ * Return the {@link FragmentActivity} this fragment is currently associated with.
+ * May return {@code null} if the fragment is associated with a {@link Context}
+ * instead.
*/
final public FragmentActivity getActivity() {
- return mActivity;
+ return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
-
+
+ /**
+ * Return the host object of this fragment. May return {@code null} if the fragment
+ * isn't currently being hosted.
+ */
+ final public Object getHost() {
+ return mHost == null ? null : mHost.onGetHost();
+ }
+
/**
* Return <code>getActivity().getResources()</code>.
*/
final public Resources getResources() {
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- return mActivity.getResources();
+ return mHost.getContext().getResources();
}
-
+
/**
* Return a localized, styled CharSequence from the application's package's
* default string table.
@@ -701,7 +720,7 @@
* Return true if the fragment is currently added to its activity.
*/
final public boolean isAdded() {
- return mActivity != null && mAdded;
+ return mHost != null && mAdded;
}
/**
@@ -812,14 +831,14 @@
* Report that this fragment would like to participate in populating
* the options menu by receiving a call to {@link #onCreateOptionsMenu}
* and related methods.
- *
+ *
* @param hasMenu If true, the fragment has menu items to contribute.
*/
public void setHasOptionsMenu(boolean hasMenu) {
if (mHasMenu != hasMenu) {
mHasMenu = hasMenu;
if (isAdded() && !isHidden()) {
- mActivity.supportInvalidateOptionsMenu();
+ mHost.onSupportInvalidateOptionsMenu();
}
}
}
@@ -837,7 +856,7 @@
if (mMenuVisible != menuVisible) {
mMenuVisible = menuVisible;
if (mHasMenu && isAdded() && !isHidden()) {
- mActivity.supportInvalidateOptionsMenu();
+ mHost.onSupportInvalidateOptionsMenu();
}
}
}
@@ -878,42 +897,42 @@
if (mLoaderManager != null) {
return mLoaderManager;
}
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, true);
return mLoaderManager;
}
-
+
/**
- * Call {@link Activity#startActivity(Intent)} on the fragment's
+ * Call {@link Activity#startActivity(Intent)} from the fragment's
* containing Activity.
*/
public void startActivity(Intent intent) {
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- mActivity.startActivityFromFragment(this, intent, -1);
+ mHost.onStartActivityFromFragment(this /*fragment*/, intent, -1);
}
-
+
/**
- * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's
+ * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's
* containing Activity.
*/
public void startActivityForResult(Intent intent, int requestCode) {
- if (mActivity == null) {
+ if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- mActivity.startActivityFromFragment(this, intent, requestCode);
+ mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode);
}
-
+
/**
* Receive the result from a previous call to
* {@link #startActivityForResult(Intent, int)}. This follows the
* related Activity API as described there in
* {@link Activity#onActivityResult(int, int, Intent)}.
- *
+ *
* @param requestCode The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
@@ -924,19 +943,137 @@
*/
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
-
+
+ /**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback on {@link
+ * #onRequestPermissionsResult(int, String[], int[])} reporting whether the
+ * permissions were granted or not.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to {@link
+ * #onRequestPermissionsResult(int, String[], int[])}.
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * android.content.Context#checkSelfPermission(String)}.
+ * </p>
+ * <p>
+ * A sample permissions request looks like this:
+ * </p>
+ * <code><pre><p>
+ * private void showContacts() {
+ * if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
+ * != PackageManager.PERMISSION_GRANTED) {
+ * requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
+ * PERMISSIONS_REQUEST_READ_CONTACTS);
+ * } else {
+ * doShowContacts();
+ * }
+ * }
+ *
+ * {@literal @}Override
+ * public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ * int[] grantResults) {
+ * if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS
+ * && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ * doShowContacts();
+ * }
+ * }
+ * </code></pre></p>
+ *
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
+ *
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ * @see android.content.Context#checkSelfPermission(String)
+ */
+ public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
+ if (mHost == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
+ mHost.onRequestPermissionsFromFragment(this, permissions,requestCode);
+ }
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(String[], int)}.
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ /* callback - do nothing */
+ }
+
+ /**
+ * Gets whether you should show UI with rationale for requesting a permission.
+ * You should do this only if you do not have the permission and the context in
+ * which the permission is requested does not clearly communicate to the user
+ * what would be the benefit from granting this permission.
+ * <p>
+ * For example, if you write a camera app, requesting the camera permission
+ * would be expected by the user and no rationale for why it is requested is
+ * needed. If however, the app needs location for tagging photos then a non-tech
+ * savvy user may wonder how location is related to taking photos. In this case
+ * you may choose to show UI with rationale of requesting this permission.
+ * </p>
+ *
+ * @param permission A permission your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ *
+ * @see Context#checkSelfPermission(String)
+ * @see #requestPermissions(String[], int)
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ */
+ public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
+ if (mHost != null) {
+ return mHost.onShouldShowRequestPermissionRationale(permission);
+ }
+ return false;
+ }
+
/**
* @hide Hack so that DialogFragment can make its Dialog before creating
* its views, and the view construction can use the dialog's context for
* inflation. Maybe this should become a public API. Note sure.
*/
public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
- LayoutInflater result = mActivity.getLayoutInflater().cloneInContext(mActivity);
+ LayoutInflater result = mHost.onGetLayoutInflater();
getChildFragmentManager(); // Init if needed; use raw implementation below.
LayoutInflaterCompat.setFactory(result, mChildFragmentManager.getLayoutInflaterFactory());
return result;
}
-
+
/**
* Called when a fragment is being created as part of a view layout
* inflation, typically from setting the content view of an activity. This
@@ -973,31 +1110,61 @@
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java
* create}
*
- * @param activity The Activity that is inflating this fragment.
+ * @param context The Activity that is inflating this fragment.
* @param attrs The attributes at the tag where the fragment is
* being created.
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
+ public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
+ mCalled = true;
+ final Activity hostActivity = mHost == null ? null : mHost.getActivity();
+ if (hostActivity != null) {
+ mCalled = false;
+ onInflate(hostActivity, attrs, savedInstanceState);
+ }
+ }
+
+ /**
+ * Called when a fragment is being created as part of a view layout
+ * inflation, typically from setting the content view of an activity.
+ * <p>Deprecated. See {@link #onInflate(Context, AttributeSet, Bundle)}.
+ */
+ @Deprecated
public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
mCalled = true;
}
/**
- * Called when a fragment is first attached to its activity.
+ * Called when a fragment is first attached to its context.
* {@link #onCreate(Bundle)} will be called after this.
*/
+ public void onAttach(Context context) {
+ mCalled = true;
+ final Activity hostActivity = mHost == null ? null : mHost.getActivity();
+ if (hostActivity != null) {
+ mCalled = false;
+ onAttach(hostActivity);
+ }
+ }
+
+ /**
+ * Called when a fragment is first attached to its activity.
+ * {@link #onCreate(Bundle)} will be called after this.
+ * <p>Deprecated. See {@link #onAttach(Context)}.
+ */
+ @Deprecated
public void onAttach(Activity activity) {
mCalled = true;
}
-
+
/**
* Called when a fragment loads an animation.
*/
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
return null;
}
-
+
/**
* Called to do initial creation of a fragment. This is called after
* {@link #onAttach(Activity)} and before
@@ -1104,19 +1271,19 @@
*/
public void onStart() {
mCalled = true;
-
+
if (!mLoadersStarted) {
mLoadersStarted = true;
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
mLoaderManager.doStart();
}
}
}
-
+
/**
* Called when the fragment is visible to the user and actively running.
* This is generally
@@ -1198,7 +1365,7 @@
// + " mLoaderManager=" + mLoaderManager);
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
mLoaderManager.doDestroy();
@@ -1223,7 +1390,7 @@
mBackStackNesting = 0;
mFragmentManager = null;
mChildFragmentManager = null;
- mActivity = null;
+ mHost = null;
mFragmentId = 0;
mContainerId = 0;
mTag = null;
@@ -1335,6 +1502,7 @@
* It is not safe to hold onto the context menu after this method returns.
* {@inheritDoc}
*/
+ @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
getActivity().onCreateContextMenu(menu, v, menuInfo);
}
@@ -1678,9 +1846,9 @@
writer.print(prefix); writer.print("mFragmentManager=");
writer.println(mFragmentManager);
}
- if (mActivity != null) {
- writer.print(prefix); writer.print("mActivity=");
- writer.println(mActivity);
+ if (mHost != null) {
+ writer.print(prefix); writer.print("mHost=");
+ writer.println(mHost);
}
if (mParentFragment != null) {
writer.print(prefix); writer.print("mParentFragment=");
@@ -1741,10 +1909,10 @@
void instantiateChildFragmentManager() {
mChildFragmentManager = new FragmentManagerImpl();
- mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
+ mChildFragmentManager.attachController(mHost, new FragmentContainer() {
@Override
@Nullable
- public View findViewById(int id) {
+ public View onFindViewById(int id) {
if (mView == null) {
throw new IllegalStateException("Fragment does not have a view");
}
@@ -1752,7 +1920,7 @@
}
@Override
- public boolean hasView() {
+ public boolean onHasView() {
return (mView != null);
}
}, this);
@@ -1974,10 +2142,10 @@
mLoadersStarted = false;
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
- mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
+ mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
- if (!mActivity.mRetaining) {
+ if (!mRetaining) {
mLoaderManager.doStop();
} else {
mLoaderManager.doRetain();
diff --git a/v4/java/android/support/v4/app/FragmentActivity.java b/v4/java/android/support/v4/app/FragmentActivity.java
index 29c6f56..9a0489c 100644
--- a/v4/java/android/support/v4/app/FragmentActivity.java
+++ b/v4/java/android/support/v4/app/FragmentActivity.java
@@ -31,6 +31,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -40,6 +41,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* Base class for activities that want to use the support-based
@@ -73,11 +75,13 @@
* state, this may be a snapshot slightly before what the user last saw.</p>
* </ul>
*/
-public class FragmentActivity extends BaseFragmentActivityHoneycomb {
+public class FragmentActivity extends BaseFragmentActivityHoneycomb implements
+ ActivityCompat.OnRequestPermissionsResultCallback,
+ ActivityCompatApi23.RequestPermissionsRequestCodeValidator {
private static final String TAG = "FragmentActivity";
-
+
static final String FRAGMENTS_TAG = "android:support:fragments";
-
+
// This is the SDK API version of Honeycomb (3.0).
private static final int HONEYCOMB = 11;
@@ -103,21 +107,8 @@
}
};
- final FragmentManagerImpl mFragments = new FragmentManagerImpl();
- final FragmentContainer mContainer = new FragmentContainer() {
- @Override
- @Nullable
- public View findViewById(int id) {
- return FragmentActivity.this.findViewById(id);
- }
+ final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
- @Override
- public boolean hasView() {
- Window window = FragmentActivity.this.getWindow();
- return (window != null && window.peekDecorView() != null);
- }
- };
-
boolean mCreated;
boolean mResumed;
boolean mStopped;
@@ -125,24 +116,18 @@
boolean mRetaining;
boolean mOptionsMenuInvalidated;
-
- boolean mCheckedForLoaderManager;
- boolean mLoadersStarted;
- SimpleArrayMap<String, LoaderManagerImpl> mAllLoaderManagers;
- LoaderManagerImpl mLoaderManager;
+ boolean mRequestedPermissionsFromFragment;
static final class NonConfigurationInstances {
- Object activity;
Object custom;
- SimpleArrayMap<String, Object> children;
- ArrayList<Fragment> fragments;
- SimpleArrayMap<String, LoaderManagerImpl> loaders;
+ List<Fragment> fragments;
+ SimpleArrayMap<String, LoaderManager> loaders;
}
-
+
// ------------------------------------------------------------------------
// HOOKS INTO ACTIVITY
// ------------------------------------------------------------------------
-
+
/**
* Dispatch incoming result to the correct fragment.
*/
@@ -152,12 +137,15 @@
int index = requestCode>>16;
if (index != 0) {
index--;
- if (mFragments.mActive == null || index < 0 || index >= mFragments.mActive.size()) {
+ final int activeFragmentsCount = mFragments.getActiveFragmentsCount();
+ if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) {
Log.w(TAG, "Activity result fragment index out of range: 0x"
+ Integer.toHexString(requestCode));
return;
}
- Fragment frag = mFragments.mActive.get(index);
+ final List<Fragment> activeFragments =
+ mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
+ Fragment frag = activeFragments.get(index);
if (frag == null) {
Log.w(TAG, "Activity result no fragment exists for index: 0x"
+ Integer.toHexString(requestCode));
@@ -166,7 +154,7 @@
}
return;
}
-
+
super.onActivityResult(requestCode, resultCode, data);
}
@@ -175,7 +163,7 @@
* as appropriate.
*/
public void onBackPressed() {
- if (!mFragments.popBackStackImmediate()) {
+ if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
supportFinishAfterTransition();
}
}
@@ -246,16 +234,17 @@
/**
* Perform initialization of all fragments and loaders.
*/
+ @SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
- mFragments.attachActivity(this, mContainer, null);
-
+ mFragments.attachHost(null /*parent*/);
+
super.onCreate(savedInstanceState);
-
- NonConfigurationInstances nc = (NonConfigurationInstances)
- getLastNonConfigurationInstance();
+
+ NonConfigurationInstances nc =
+ (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
- mAllLoaderManagers = nc.loaders;
+ mFragments.restoreLoaderNonConfig(nc.loaders);
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
@@ -299,9 +288,7 @@
doReallyStop(false);
mFragments.dispatchDestroy();
- if (mLoaderManager != null) {
- mLoaderManager.doDestroy();
- }
+ mFragments.doLoaderDestroy();
}
/**
@@ -470,36 +457,17 @@
Object custom = onRetainCustomNonConfigurationInstance();
- ArrayList<Fragment> fragments = mFragments.retainNonConfig();
- boolean retainLoaders = false;
- if (mAllLoaderManagers != null) {
- // prune out any loader managers that were already stopped and so
- // have nothing useful to retain.
- final int N = mAllLoaderManagers.size();
- LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
- for (int i=N-1; i>=0; i--) {
- loaders[i] = mAllLoaderManagers.valueAt(i);
- }
- for (int i=0; i<N; i++) {
- LoaderManagerImpl lm = loaders[i];
- if (lm.mRetaining) {
- retainLoaders = true;
- } else {
- lm.doDestroy();
- mAllLoaderManagers.remove(lm.mWho);
- }
- }
- }
- if (fragments == null && !retainLoaders && custom == null) {
+ List<Fragment> fragments = mFragments.retainNonConfig();
+ SimpleArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
+
+ if (fragments == null && loaders == null && custom == null) {
return null;
}
-
+
NonConfigurationInstances nci = new NonConfigurationInstances();
- nci.activity = null;
nci.custom = custom;
- nci.children = null;
nci.fragments = fragments;
- nci.loaders = mAllLoaderManagers;
+ nci.loaders = loaders;
return nci;
}
@@ -534,35 +502,13 @@
mFragments.noteStateNotSaved();
mFragments.execPendingActions();
-
- if (!mLoadersStarted) {
- mLoadersStarted = true;
- if (mLoaderManager != null) {
- mLoaderManager.doStart();
- } else if (!mCheckedForLoaderManager) {
- mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
- // the returned loader manager may be a new one, so we have to start it
- if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
- mLoaderManager.doStart();
- }
- }
- mCheckedForLoaderManager = true;
- }
+
+ mFragments.doLoaderStart();
+
// NOTE: HC onStart goes here.
-
+
mFragments.dispatchStart();
- if (mAllLoaderManagers != null) {
- final int N = mAllLoaderManagers.size();
- LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
- for (int i=N-1; i>=0; i--) {
- loaders[i] = mAllLoaderManagers.valueAt(i);
- }
- for (int i=0; i<N; i++) {
- LoaderManagerImpl lm = loaders[i];
- lm.finishRetain();
- lm.doReportStart();
- }
- }
+ mFragments.reportLoaderStart();
}
/**
@@ -574,14 +520,14 @@
mStopped = true;
mHandler.sendEmptyMessage(MSG_REALLY_STOPPED);
-
+
mFragments.dispatchStop();
}
// ------------------------------------------------------------------------
// NEW METHODS
// ------------------------------------------------------------------------
-
+
/**
* Use this instead of {@link #onRetainNonConfigurationInstance()}.
* Retrieve later with {@link #getLastCustomNonConfigurationInstance()}.
@@ -594,6 +540,7 @@
* Return the value previously returned from
* {@link #onRetainCustomNonConfigurationInstance()}.
*/
+ @SuppressWarnings("deprecation")
public Object getLastCustomNonConfigurationInstance() {
NonConfigurationInstances nc = (NonConfigurationInstances)
getLastNonConfigurationInstance();
@@ -644,15 +591,8 @@
writer.print(mResumed); writer.print(" mStopped=");
writer.print(mStopped); writer.print(" mReallyStopped=");
writer.println(mReallyStopped);
- writer.print(innerPrefix); writer.print("mLoadersStarted=");
- writer.println(mLoadersStarted);
- if (mLoaderManager != null) {
- writer.print(prefix); writer.print("Loader Manager ");
- writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
- writer.println(":");
- mLoaderManager.dump(prefix + " ", fd, writer, args);
- }
- mFragments.dump(prefix, fd, writer, args);
+ mFragments.dumpLoaders(innerPrefix, fd, writer, args);
+ mFragments.getSupportFragmentManager().dump(prefix, fd, writer, args);
writer.print(prefix); writer.println("View Hierarchy:");
dumpViewHierarchy(prefix + " ", writer, getWindow().getDecorView());
}
@@ -761,16 +701,7 @@
* tell us what we need to know.
*/
void onReallyStop() {
- if (mLoadersStarted) {
- mLoadersStarted = false;
- if (mLoaderManager != null) {
- if (!mRetaining) {
- mLoaderManager.doStop();
- } else {
- mLoaderManager.doRetain();
- }
- }
- }
+ mFragments.doLoaderStop(mRetaining);
mFragments.dispatchReallyStop();
}
@@ -778,19 +709,24 @@
// ------------------------------------------------------------------------
// FRAGMENT SUPPORT
// ------------------------------------------------------------------------
-
+
/**
* Called when a fragment is attached to the activity.
*/
+ @SuppressWarnings("unused")
public void onAttachFragment(Fragment fragment) {
}
-
+
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
*/
public FragmentManager getSupportFragmentManager() {
- return mFragments;
+ return mFragments.getSupportFragmentManager();
+ }
+
+ public LoaderManager getSupportLoaderManager() {
+ return mFragments.getSupportLoaderManager();
}
/**
@@ -805,10 +741,61 @@
super.startActivityForResult(intent, requestCode);
}
+ @Override
+ public final void validateRequestPermissionsRequestCode(int requestCode) {
+ // We use 8 bits of the request code to encode the fragment id when
+ // requesting permissions from a fragment. Hence, requestPermissions()
+ // should validate the code against that but we cannot override it as
+ // we can not then call super and also the ActivityCompat would call
+ // back to this override. To handle this we use dependency inversion
+ // where we are the validator of request codes when requesting
+ // permissions in ActivityCompat.
+ if (mRequestedPermissionsFromFragment) {
+ mRequestedPermissionsFromFragment = false;
+ } else if ((requestCode & 0xffffff00) != 0) {
+ throw new IllegalArgumentException("Can only use lower 8 bits for requestCode");
+ }
+ }
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(String[], int)}.
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ int index = (requestCode>>8)&0xff;
+ if (index != 0) {
+ index--;
+ final int activeFragmentsCount = mFragments.getActiveFragmentsCount();
+ if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) {
+ Log.w(TAG, "Activity result fragment index out of range: 0x"
+ + Integer.toHexString(requestCode));
+ return;
+ }
+ final List<Fragment> activeFragments =
+ mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
+ Fragment frag = activeFragments.get(index);
+ if (frag == null) {
+ Log.w(TAG, "Activity result no fragment exists for index: 0x"
+ + Integer.toHexString(requestCode));
+ } else {
+ frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
+ }
+ }
+ }
+
/**
* Called by Fragment.startActivityForResult() to implement its behavior.
*/
- public void startActivityFromFragment(Fragment fragment, Intent intent,
+ public void startActivityFromFragment(Fragment fragment, Intent intent,
int requestCode) {
if (requestCode == -1) {
super.startActivityForResult(intent, -1);
@@ -819,47 +806,98 @@
}
super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff));
}
-
- void invalidateSupportFragment(String who) {
- //Log.v(TAG, "invalidateSupportFragment: who=" + who);
- if (mAllLoaderManagers != null) {
- LoaderManagerImpl lm = mAllLoaderManagers.get(who);
- if (lm != null && !lm.mRetaining) {
- lm.doDestroy();
- mAllLoaderManagers.remove(who);
- }
- }
- }
-
- // ------------------------------------------------------------------------
- // LOADER SUPPORT
- // ------------------------------------------------------------------------
-
+
/**
- * Return the LoaderManager for this fragment, creating it if needed.
+ * Called by Fragment.requestPermissions() to implement its behavior.
*/
- public LoaderManager getSupportLoaderManager() {
- if (mLoaderManager != null) {
- return mLoaderManager;
+ private void requestPermissionsFromFragment(Fragment fragment, String[] permissions,
+ int requestCode) {
+ if (requestCode == -1) {
+ ActivityCompat.requestPermissions(this, permissions, requestCode);
+ return;
}
- mCheckedForLoaderManager = true;
- mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
- return mLoaderManager;
+ if ((requestCode&0xffffff00) != 0) {
+ throw new IllegalArgumentException("Can only use lower 8 bits for requestCode");
+ }
+ mRequestedPermissionsFromFragment = true;
+ ActivityCompat.requestPermissions(this, permissions,
+ ((fragment.mIndex + 1) << 8) + (requestCode & 0xff));
}
-
- LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
- if (mAllLoaderManagers == null) {
- mAllLoaderManagers = new SimpleArrayMap<String, LoaderManagerImpl>();
+
+ class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
+ public HostCallbacks() {
+ super(FragmentActivity.this /*fragmentActivity*/);
}
- LoaderManagerImpl lm = mAllLoaderManagers.get(who);
- if (lm == null) {
- if (create) {
- lm = new LoaderManagerImpl(who, this, started);
- mAllLoaderManagers.put(who, lm);
- }
- } else {
- lm.updateActivity(this);
+
+ @Override
+ public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ FragmentActivity.this.dump(prefix, fd, writer, args);
}
- return lm;
+
+ @Override
+ public boolean onShouldSaveFragmentState(Fragment fragment) {
+ return !isFinishing();
+ }
+
+ @Override
+ public LayoutInflater onGetLayoutInflater() {
+ return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this);
+ }
+
+ @Override
+ public FragmentActivity onGetHost() {
+ return FragmentActivity.this;
+ }
+
+ @Override
+ public void onSupportInvalidateOptionsMenu() {
+ FragmentActivity.this.supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
+ FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);
+ }
+
+ @Override
+ public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
+ @NonNull String[] permissions, int requestCode) {
+ FragmentActivity.this.requestPermissionsFromFragment(fragment, permissions,
+ requestCode);
+ }
+
+ @Override
+ public boolean onShouldShowRequestPermissionRationale(@NonNull String permission) {
+ return ActivityCompat.shouldShowRequestPermissionRationale(
+ FragmentActivity.this, permission);
+ }
+
+ @Override
+ public boolean onHasWindowAnimations() {
+ return getWindow() != null;
+ }
+
+ @Override
+ public int onGetWindowAnimations() {
+ final Window w = getWindow();
+ return (w == null) ? 0 : w.getAttributes().windowAnimations;
+ }
+
+ @Override
+ public void onAttachFragment(Fragment fragment) {
+ FragmentActivity.this.onAttachFragment(fragment);
+ }
+
+ @Nullable
+ @Override
+ public View onFindViewById(int id) {
+ return FragmentActivity.this.findViewById(id);
+ }
+
+ @Override
+ public boolean onHasView() {
+ final Window w = getWindow();
+ return (w != null && w.peekDecorView() != null);
+ }
}
}
diff --git a/v4/java/android/support/v4/app/FragmentContainer.java b/v4/java/android/support/v4/app/FragmentContainer.java
new file mode 100644
index 0000000..1367540
--- /dev/null
+++ b/v4/java/android/support/v4/app/FragmentContainer.java
@@ -0,0 +1,23 @@
+package android.support.v4.app;
+
+import android.support.annotation.IdRes;
+import android.support.annotation.Nullable;
+import android.view.View;
+
+
+/**
+ * Callbacks to a {@link Fragment}'s container.
+ */
+public abstract class FragmentContainer {
+ /**
+ * Return the view with the given resource ID. May return {@code null} if the
+ * view is not a child of this container.
+ */
+ @Nullable
+ public abstract View onFindViewById(@IdRes int id);
+
+ /**
+ * Return {@code true} if the container holds any view.
+ */
+ public abstract boolean onHasView();
+}
diff --git a/v4/java/android/support/v4/app/FragmentController.java b/v4/java/android/support/v4/app/FragmentController.java
new file mode 100644
index 0000000..5d647b0
--- /dev/null
+++ b/v4/java/android/support/v4/app/FragmentController.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Parcelable;
+import android.support.v4.util.SimpleArrayMap;
+import android.util.AttributeSet;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides integration points with a {@link FragmentManager} for a fragment host.
+ * <p>
+ * It is the responsibility of the host to take care of the Fragment's lifecycle.
+ * The methods provided by {@link FragmentController} are for that purpose.
+ */
+public class FragmentController {
+ private final FragmentHostCallback<?> mHost;
+
+ /**
+ * Returns a {@link FragmentController}.
+ */
+ public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
+ return new FragmentController(callbacks);
+ }
+
+ private FragmentController(FragmentHostCallback<?> callbacks) {
+ mHost = callbacks;
+ }
+
+ /**
+ * Returns a {@link FragmentManager} for this controller.
+ */
+ public FragmentManager getSupportFragmentManager() {
+ return mHost.getFragmentManagerImpl();
+ }
+
+ /**
+ * Returns a {@link LoaderManager}.
+ */
+ public LoaderManager getSupportLoaderManager() {
+ return mHost.getLoaderManagerImpl();
+ }
+
+ /**
+ * Returns the number of active fragments.
+ */
+ public int getActiveFragmentsCount() {
+ final List<Fragment> actives = mHost.mFragmentManager.mActive;
+ return actives == null ? 0 : actives.size();
+ }
+
+ /**
+ * Returns the list of active fragments.
+ */
+ public List<Fragment> getActiveFragments(List<Fragment> actives) {
+ if (mHost.mFragmentManager.mActive == null) {
+ return null;
+ }
+ if (actives == null) {
+ actives = new ArrayList<Fragment>(getActiveFragmentsCount());
+ }
+ actives.addAll(mHost.mFragmentManager.mActive);
+ return actives;
+ }
+
+ /**
+ * Attaches the host to the FragmentManager for this controller. The host must be
+ * attached before the FragmentManager can be used to manage Fragments.
+ */
+ public void attachHost(Fragment parent) {
+ mHost.mFragmentManager.attachController(
+ mHost, mHost /*container*/, parent);
+ }
+
+ /**
+ * Instantiates a Fragment's view.
+ *
+ * @param parent The parent that the created view will be placed
+ * in; <em>note that this may be null</em>.
+ * @param name Tag name to be inflated.
+ * @param context The context the view is being created in.
+ * @param attrs Inflation attributes as specified in XML file.
+ *
+ * @return view the newly created view
+ */
+ public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+ return mHost.mFragmentManager.onCreateView(parent, name, context, attrs);
+ }
+
+ /**
+ * Marks the fragment state as unsaved. This allows for "state loss" detection.
+ */
+ public void noteStateNotSaved() {
+ mHost.mFragmentManager.noteStateNotSaved();
+ }
+
+ /**
+ * Saves the state for all Fragments.
+ */
+ public Parcelable saveAllState() {
+ return mHost.mFragmentManager.saveAllState();
+ }
+
+ /**
+ * Restores the saved state for all Fragments. The given Fragment list are Fragment
+ * instances retained across configuration changes.
+ *
+ * @see #retainNonConfig()
+ */
+ public void restoreAllState(Parcelable state, List<Fragment> nonConfigList) {
+ mHost.mFragmentManager.restoreAllState(state, nonConfigList);
+ }
+
+ /**
+ * Returns a list of Fragments that have opted to retain their instance across
+ * configuration changes.
+ */
+ public List<Fragment> retainNonConfig() {
+ return mHost.mFragmentManager.retainNonConfig();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the create state.
+ * <p>Call when Fragments should be created.
+ *
+ * @see Fragment#onCreate(Bundle)
+ */
+ public void dispatchCreate() {
+ mHost.mFragmentManager.dispatchCreate();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the activity created state.
+ * <p>Call when Fragments should be informed their host has been created.
+ *
+ * @see Fragment#onActivityCreated(Bundle)
+ */
+ public void dispatchActivityCreated() {
+ mHost.mFragmentManager.dispatchActivityCreated();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the start state.
+ * <p>Call when Fragments should be started.
+ *
+ * @see Fragment#onStart()
+ */
+ public void dispatchStart() {
+ mHost.mFragmentManager.dispatchStart();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the resume state.
+ * <p>Call when Fragments should be resumed.
+ *
+ * @see Fragment#onResume()
+ */
+ public void dispatchResume() {
+ mHost.mFragmentManager.dispatchResume();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the pause state.
+ * <p>Call when Fragments should be paused.
+ *
+ * @see Fragment#onPause()
+ */
+ public void dispatchPause() {
+ mHost.mFragmentManager.dispatchPause();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the stop state.
+ * <p>Call when Fragments should be stopped.
+ *
+ * @see Fragment#onStop()
+ */
+ public void dispatchStop() {
+ mHost.mFragmentManager.dispatchStop();
+ }
+
+ public void dispatchReallyStop() {
+ mHost.mFragmentManager.dispatchReallyStop();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the destroy view state.
+ * <p>Call when the Fragment's views should be destroyed.
+ *
+ * @see Fragment#onDestroyView()
+ */
+ public void dispatchDestroyView() {
+ mHost.mFragmentManager.dispatchDestroyView();
+ }
+
+ /**
+ * Moves all Fragments managed by the controller's FragmentManager
+ * into the destroy state.
+ * <p>Call when Fragments should be destroyed.
+ *
+ * @see Fragment#onDestroy()
+ */
+ public void dispatchDestroy() {
+ mHost.mFragmentManager.dispatchDestroy();
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know a configuration change occurred.
+ * <p>Call when there is a configuration change.
+ *
+ * @see Fragment#onConfigurationChanged(Configuration)
+ */
+ public void dispatchConfigurationChanged(Configuration newConfig) {
+ mHost.mFragmentManager.dispatchConfigurationChanged(newConfig);
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know the device is in a low memory condition.
+ * <p>Call when the device is low on memory and Fragment's should trim
+ * their memory usage.
+ *
+ * @see Fragment#onLowMemory()
+ */
+ public void dispatchLowMemory() {
+ mHost.mFragmentManager.dispatchLowMemory();
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know they should create an options menu.
+ * <p>Call when the Fragment should create an options menu.
+ *
+ * @return {@code true} if the options menu contains items to display
+ * @see Fragment#onCreateOptionsMenu(Menu, MenuInflater)
+ */
+ public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ return mHost.mFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know they should prepare their options menu for display.
+ * <p>Call immediately before displaying the Fragment's options menu.
+ *
+ * @return {@code true} if the options menu contains items to display
+ * @see Fragment#onPrepareOptionsMenu(Menu)
+ */
+ public boolean dispatchPrepareOptionsMenu(Menu menu) {
+ return mHost.mFragmentManager.dispatchPrepareOptionsMenu(menu);
+ }
+
+ /**
+ * Sends an option item selection event to the Fragments managed by the
+ * controller's FragmentManager. Once the event has been consumed,
+ * no additional handling will be performed.
+ * <p>Call immediately after an options menu item has been selected
+ *
+ * @return {@code true} if the options menu selection event was consumed
+ * @see Fragment#onOptionsItemSelected(MenuItem)
+ */
+ public boolean dispatchOptionsItemSelected(MenuItem item) {
+ return mHost.mFragmentManager.dispatchOptionsItemSelected(item);
+ }
+
+ /**
+ * Sends a context item selection event to the Fragments managed by the
+ * controller's FragmentManager. Once the event has been consumed,
+ * no additional handling will be performed.
+ * <p>Call immediately after an options menu item has been selected
+ *
+ * @return {@code true} if the context menu selection event was consumed
+ * @see Fragment#onContextItemSelected(MenuItem)
+ */
+ public boolean dispatchContextItemSelected(MenuItem item) {
+ return mHost.mFragmentManager.dispatchContextItemSelected(item);
+ }
+
+ /**
+ * Lets all Fragments managed by the controller's FragmentManager
+ * know their options menu has closed.
+ * <p>Call immediately after closing the Fragment's options menu.
+ *
+ * @see Fragment#onOptionsMenuClosed(Menu)
+ */
+ public void dispatchOptionsMenuClosed(Menu menu) {
+ mHost.mFragmentManager.dispatchOptionsMenuClosed(menu);
+ }
+
+ /**
+ * Execute any pending actions for the Fragments managed by the
+ * controller's FragmentManager.
+ * <p>Call when queued actions can be performed [eg when the
+ * Fragment moves into a start or resume state].
+ * @return {@code true} if queued actions were performed
+ */
+ public boolean execPendingActions() {
+ return mHost.mFragmentManager.execPendingActions();
+ }
+
+ /**
+ * Starts the loaders.
+ */
+ public void doLoaderStart() {
+ mHost.doLoaderStart();
+ }
+
+ /**
+ * Stops the loaders, optionally retaining their state. This is useful for keeping the
+ * loader state across configuration changes.
+ *
+ * @param retain When {@code true}, the loaders aren't stopped, but, their instances
+ * are retained in a started state
+ */
+ public void doLoaderStop(boolean retain) {
+ mHost.doLoaderStop(retain);
+ }
+
+ /**
+ * Retains the state of each of the loaders.
+ */
+ public void doLoaderRetain() {
+ mHost.doLoaderRetain();
+ }
+
+ /**
+ * Destroys the loaders and, if their state is not being retained, removes them.
+ */
+ public void doLoaderDestroy() {
+ mHost.doLoaderDestroy();
+ }
+
+ /**
+ * Lets the loaders know the host is ready to receive notifications.
+ */
+ public void reportLoaderStart() {
+ mHost.reportLoaderStart();
+ }
+
+ /**
+ * Returns a list of LoaderManagers that have opted to retain their instance across
+ * configuration changes.
+ */
+ public SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() {
+ return mHost.retainLoaderNonConfig();
+ }
+
+ /**
+ * Restores the saved state for all LoaderManagers. The given LoaderManager list are
+ * LoaderManager instances retained across configuration changes.
+ *
+ * @see #retainLoaderNonConfig()
+ */
+ public void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
+ mHost.restoreLoaderNonConfig(loaderManagers);
+ }
+
+ /**
+ * Dumps the current state of the loaders.
+ */
+ public void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ mHost.dumpLoaders(prefix, fd, writer, args);
+ }
+}
diff --git a/v4/java/android/support/v4/app/FragmentHostCallback.java b/v4/java/android/support/v4/app/FragmentHostCallback.java
new file mode 100644
index 0000000..fb4410f
--- /dev/null
+++ b/v4/java/android/support/v4/app/FragmentHostCallback.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.SimpleArrayMap;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Integration points with the Fragment host.
+ * <p>
+ * Fragments may be hosted by any object; such as an {@link Activity}. In order to
+ * host fragments, implement {@link FragmentHostCallback}, overriding the methods
+ * applicable to the host.
+ */
+public abstract class FragmentHostCallback<E> extends FragmentContainer {
+ private final Activity mActivity;
+ final Context mContext;
+ private final Handler mHandler;
+ final int mWindowAnimations;
+ final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
+ private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;
+ private LoaderManagerImpl mLoaderManager;
+ private boolean mCheckedForLoaderManager;
+ private boolean mLoadersStarted;
+
+ public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
+ this(null /*activity*/, context, handler, windowAnimations);
+ }
+
+ FragmentHostCallback(FragmentActivity activity) {
+ this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
+ }
+
+ FragmentHostCallback(Activity activity, Context context, Handler handler,
+ int windowAnimations) {
+ mActivity = activity;
+ mContext = context;
+ mHandler = handler;
+ mWindowAnimations = windowAnimations;
+ }
+
+ /**
+ * Print internal state into the given stream.
+ *
+ * @param prefix Desired prefix to prepend at each line of output.
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param writer The PrintWriter to which you should dump your state. This will be closed
+ * for you after you return.
+ * @param args additional arguments to the dump request.
+ */
+ public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ }
+
+ /**
+ * Return {@code true} if the fragment's state needs to be saved.
+ */
+ public boolean onShouldSaveFragmentState(Fragment fragment) {
+ return true;
+ }
+
+ /**
+ * Return a {@link LayoutInflater}.
+ * See {@link Activity#getLayoutInflater()}.
+ */
+ public LayoutInflater onGetLayoutInflater() {
+ return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ /**
+ * Return the object that's currently hosting the fragment. If a {@link Fragment}
+ * is hosted by a {@link FragmentActivity}, the object returned here should be
+ * the same object returned from {@link Fragment#getActivity()}.
+ */
+ @Nullable
+ public abstract E onGetHost();
+
+ /**
+ * Invalidates the activity's options menu.
+ * See {@link FragmentActivity#supportInvalidateOptionsMenu()}
+ */
+ public void onSupportInvalidateOptionsMenu() {
+ }
+
+ /**
+ * Starts a new {@link Activity} from the given fragment.
+ * See {@link FragmentActivity#startActivityForResult(Intent, int)}.
+ */
+ public void onStartActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
+ if (requestCode != -1) {
+ throw new IllegalStateException(
+ "Starting activity with a requestCode requires a FragmentActivity host");
+ }
+ mContext.startActivity(intent);
+ }
+
+ /**
+ * Requests permissions from the given fragment.
+ * See {@link FragmentActivity#requestPermissions(String[], int)}
+ */
+ public void onRequestPermissionsFromFragment(@NonNull Fragment fragment,
+ @NonNull String[] permissions, int requestCode) {
+ }
+
+ /**
+ * Checks wehter to show permission rationale UI from a fragment.
+ * See {@link FragmentActivity#shouldShowRequestPermissionRationale(String)}
+ */
+ public boolean onShouldShowRequestPermissionRationale(@NonNull String permission) {
+ return false;
+ }
+
+ /**
+ * Return {@code true} if there are window animations.
+ */
+ public boolean onHasWindowAnimations() {
+ return true;
+ }
+
+ /**
+ * Return the window animations.
+ */
+ public int onGetWindowAnimations() {
+ return mWindowAnimations;
+ }
+
+ @Nullable
+ @Override
+ public View onFindViewById(int id) {
+ return null;
+ }
+
+ @Override
+ public boolean onHasView() {
+ return true;
+ }
+
+ Activity getActivity() {
+ return mActivity;
+ }
+
+ Context getContext() {
+ return mContext;
+ }
+
+ Handler getHandler() {
+ return mHandler;
+ }
+
+ FragmentManagerImpl getFragmentManagerImpl() {
+ return mFragmentManager;
+ }
+
+ LoaderManagerImpl getLoaderManagerImpl() {
+ if (mLoaderManager != null) {
+ return mLoaderManager;
+ }
+ mCheckedForLoaderManager = true;
+ mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
+ return mLoaderManager;
+ }
+
+ void inactivateFragment(String who) {
+ //Log.v(TAG, "invalidateSupportFragment: who=" + who);
+ if (mAllLoaderManagers != null) {
+ LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
+ if (lm != null && !lm.mRetaining) {
+ lm.doDestroy();
+ mAllLoaderManagers.remove(who);
+ }
+ }
+ }
+
+ void onAttachFragment(Fragment fragment) {
+ }
+
+ void doLoaderStart() {
+ if (mLoadersStarted) {
+ return;
+ }
+ mLoadersStarted = true;
+
+ if (mLoaderManager != null) {
+ mLoaderManager.doStart();
+ } else if (!mCheckedForLoaderManager) {
+ mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
+ // the returned loader manager may be a new one, so we have to start it
+ if ((mLoaderManager != null) && (!mLoaderManager.mStarted)) {
+ mLoaderManager.doStart();
+ }
+ }
+ mCheckedForLoaderManager = true;
+ }
+
+ // retain -- whether to stop the loader or retain it
+ void doLoaderStop(boolean retain) {
+ if (mLoaderManager == null) {
+ return;
+ }
+
+ if (!mLoadersStarted) {
+ return;
+ }
+ mLoadersStarted = false;
+
+ if (retain) {
+ mLoaderManager.doRetain();
+ } else {
+ mLoaderManager.doStop();
+ }
+ }
+
+ void doLoaderRetain() {
+ if (mLoaderManager == null) {
+ return;
+ }
+ mLoaderManager.doRetain();
+ }
+
+ void doLoaderDestroy() {
+ if (mLoaderManager == null) {
+ return;
+ }
+ mLoaderManager.doDestroy();
+ }
+
+ void reportLoaderStart() {
+ if (mAllLoaderManagers != null) {
+ final int N = mAllLoaderManagers.size();
+ LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+ for (int i=N-1; i>=0; i--) {
+ loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
+ }
+ for (int i=0; i<N; i++) {
+ LoaderManagerImpl lm = loaders[i];
+ lm.finishRetain();
+ lm.doReportStart();
+ }
+ }
+ }
+
+ LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
+ if (mAllLoaderManagers == null) {
+ mAllLoaderManagers = new SimpleArrayMap<String, LoaderManager>();
+ }
+ LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
+ if (lm == null) {
+ if (create) {
+ lm = new LoaderManagerImpl(who, this, started);
+ mAllLoaderManagers.put(who, lm);
+ }
+ } else {
+ lm.updateHostController(this);
+ }
+ return lm;
+ }
+
+ SimpleArrayMap<String, LoaderManager> retainLoaderNonConfig() {
+ boolean retainLoaders = false;
+ if (mAllLoaderManagers != null) {
+ // prune out any loader managers that were already stopped and so
+ // have nothing useful to retain.
+ final int N = mAllLoaderManagers.size();
+ LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];
+ for (int i=N-1; i>=0; i--) {
+ loaders[i] = (LoaderManagerImpl) mAllLoaderManagers.valueAt(i);
+ }
+ for (int i=0; i<N; i++) {
+ LoaderManagerImpl lm = loaders[i];
+ if (lm.mRetaining) {
+ retainLoaders = true;
+ } else {
+ lm.doDestroy();
+ mAllLoaderManagers.remove(lm.mWho);
+ }
+ }
+ }
+
+ if (retainLoaders) {
+ return mAllLoaderManagers;
+ }
+ return null;
+ }
+
+ void restoreLoaderNonConfig(SimpleArrayMap<String, LoaderManager> loaderManagers) {
+ mAllLoaderManagers = loaderManagers;
+ }
+
+ void dumpLoaders(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ writer.print(prefix); writer.print("mLoadersStarted=");
+ writer.println(mLoadersStarted);
+ if (mLoaderManager != null) {
+ writer.print(prefix); writer.print("Loader Manager ");
+ writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager)));
+ writer.println(":");
+ mLoaderManager.dump(prefix + " ", fd, writer, args);
+ }
+ }
+}
diff --git a/v4/java/android/support/v4/app/FragmentManager.java b/v4/java/android/support/v4/app/FragmentManager.java
index 6d41d45..94d8243 100644
--- a/v4/java/android/support/v4/app/FragmentManager.java
+++ b/v4/java/android/support/v4/app/FragmentManager.java
@@ -25,8 +25,8 @@
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.CallSuper;
import android.support.annotation.IdRes;
-import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.util.DebugUtils;
import android.support.v4.util.LogWriter;
@@ -399,15 +399,6 @@
}
/**
- * Callbacks from FragmentManagerImpl to its container.
- */
-interface FragmentContainer {
- @Nullable
- public View findViewById(@IdRes int id);
- public boolean hasView();
-}
-
-/**
* Container for fragments associated with an activity.
*/
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
@@ -421,6 +412,39 @@
static final String VIEW_STATE_TAG = "android:view_state";
static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
+
+ static class AnimateOnHWLayerIfNeededListener implements AnimationListener {
+ private boolean mShouldRunOnHWLayer = false;
+ private View mView;
+ public AnimateOnHWLayerIfNeededListener(final View v, Animation anim) {
+ if (v == null || anim == null) {
+ return;
+ }
+ mView = v;
+ }
+
+ @Override
+ @CallSuper
+ public void onAnimationStart(Animation animation) {
+ mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
+ if (mShouldRunOnHWLayer) {
+ ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_HARDWARE, null);
+ }
+ }
+
+ @Override
+ @CallSuper
+ public void onAnimationEnd(Animation animation) {
+ if (mShouldRunOnHWLayer) {
+ ViewCompat.setLayerType(mView, ViewCompat.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ }
+
ArrayList<Runnable> mPendingActions;
Runnable[] mTmpActions;
boolean mExecutingActions;
@@ -438,7 +462,8 @@
ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
int mCurState = Fragment.INITIALIZING;
- FragmentActivity mActivity;
+ FragmentHostCallback mHost;
+ FragmentController mController;
FragmentContainer mContainer;
Fragment mParent;
@@ -459,14 +484,34 @@
}
};
+ static boolean modifiesAlpha(Animation anim) {
+ if (anim instanceof AlphaAnimation) {
+ return true;
+ } else if (anim instanceof AnimationSet) {
+ List<Animation> anims = ((AnimationSet) anim).getAnimations();
+ for (int i = 0; i < anims.size(); i++) {
+ if (anims.get(i) instanceof AlphaAnimation) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ static boolean shouldRunOnHWLayer(View v, Animation anim) {
+ return ViewCompat.getLayerType(v) == ViewCompat.LAYER_TYPE_NONE
+ && ViewCompat.hasOverlappingRendering(v)
+ && modifiesAlpha(anim);
+ }
+
private void throwException(RuntimeException ex) {
Log.e(TAG, ex.getMessage());
Log.e(TAG, "Activity state:");
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
- if (mActivity != null) {
+ if (mHost != null) {
try {
- mActivity.dump(" ", null, pw, new String[] { });
+ mHost.onDump(" ", null, pw, new String[] { });
} catch (Exception e) {
Log.e(TAG, "Failed dumping state", e);
}
@@ -494,7 +539,7 @@
public void popBackStack() {
enqueueAction(new Runnable() {
@Override public void run() {
- popBackStackState(mActivity.mHandler, null, -1, 0);
+ popBackStackState(mHost.getHandler(), null, -1, 0);
}
}, false);
}
@@ -503,14 +548,14 @@
public boolean popBackStackImmediate() {
checkStateLoss();
executePendingTransactions();
- return popBackStackState(mActivity.mHandler, null, -1, 0);
+ return popBackStackState(mHost.getHandler(), null, -1, 0);
}
@Override
public void popBackStack(final String name, final int flags) {
enqueueAction(new Runnable() {
@Override public void run() {
- popBackStackState(mActivity.mHandler, name, -1, flags);
+ popBackStackState(mHost.getHandler(), name, -1, flags);
}
}, false);
}
@@ -519,7 +564,7 @@
public boolean popBackStackImmediate(String name, int flags) {
checkStateLoss();
executePendingTransactions();
- return popBackStackState(mActivity.mHandler, name, -1, flags);
+ return popBackStackState(mHost.getHandler(), name, -1, flags);
}
@Override
@@ -529,7 +574,7 @@
}
enqueueAction(new Runnable() {
@Override public void run() {
- popBackStackState(mActivity.mHandler, null, id, flags);
+ popBackStackState(mHost.getHandler(), null, id, flags);
}
}, false);
}
@@ -541,7 +586,7 @@
if (id < 0) {
throw new IllegalArgumentException("Bad id: " + id);
}
- return popBackStackState(mActivity.mHandler, null, id, flags);
+ return popBackStackState(mHost.getHandler(), null, id, flags);
}
@Override
@@ -628,7 +673,7 @@
if (mParent != null) {
DebugUtils.buildShortClassTag(mParent, sb);
} else {
- DebugUtils.buildShortClassTag(mActivity, sb);
+ DebugUtils.buildShortClassTag(mHost, sb);
}
sb.append("}}");
return sb.toString();
@@ -725,7 +770,7 @@
}
writer.print(prefix); writer.println("FragmentManager misc state:");
- writer.print(prefix); writer.print(" mActivity="); writer.println(mActivity);
+ writer.print(prefix); writer.print(" mHost="); writer.println(mHost);
writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
if (mParent != null) {
writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
@@ -775,7 +820,7 @@
anim.setDuration(ANIM_DUR);
return anim;
}
-
+
Animation loadAnimation(Fragment fragment, int transit, boolean enter,
int transitionStyle) {
Animation animObj = fragment.onCreateAnimation(transit, enter,
@@ -785,7 +830,7 @@
}
if (fragment.mNextAnim != 0) {
- Animation anim = AnimationUtils.loadAnimation(mActivity, fragment.mNextAnim);
+ Animation anim = AnimationUtils.loadAnimation(mHost.getContext(), fragment.mNextAnim);
if (anim != null) {
return anim;
}
@@ -799,24 +844,24 @@
if (styleIndex < 0) {
return null;
}
-
+
switch (styleIndex) {
case ANIM_STYLE_OPEN_ENTER:
- return makeOpenCloseAnimation(mActivity, 1.125f, 1.0f, 0, 1);
+ return makeOpenCloseAnimation(mHost.getContext(), 1.125f, 1.0f, 0, 1);
case ANIM_STYLE_OPEN_EXIT:
- return makeOpenCloseAnimation(mActivity, 1.0f, .975f, 1, 0);
+ return makeOpenCloseAnimation(mHost.getContext(), 1.0f, .975f, 1, 0);
case ANIM_STYLE_CLOSE_ENTER:
- return makeOpenCloseAnimation(mActivity, .975f, 1.0f, 0, 1);
+ return makeOpenCloseAnimation(mHost.getContext(), .975f, 1.0f, 0, 1);
case ANIM_STYLE_CLOSE_EXIT:
- return makeOpenCloseAnimation(mActivity, 1.0f, 1.075f, 1, 0);
+ return makeOpenCloseAnimation(mHost.getContext(), 1.0f, 1.075f, 1, 0);
case ANIM_STYLE_FADE_ENTER:
- return makeFadeAnimation(mActivity, 0, 1);
+ return makeFadeAnimation(mHost.getContext(), 0, 1);
case ANIM_STYLE_FADE_EXIT:
- return makeFadeAnimation(mActivity, 1, 0);
+ return makeFadeAnimation(mHost.getContext(), 1, 0);
}
- if (transitionStyle == 0 && mActivity.getWindow() != null) {
- transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
+ if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
+ transitionStyle = mHost.onGetWindowAnimations();
}
if (transitionStyle == 0) {
return null;
@@ -847,6 +892,22 @@
}
}
+ /**
+ * Sets the to be animated view on hardware layer during the animation. Note
+ * that calling this will replace any existing animation listener on the animation
+ * with a new one, as animations do not support more than one listeners. Therefore,
+ * animations that already have listeners should do the layer change operations
+ * in their existing listeners, rather than calling this function.
+ */
+ private void setHWLayerAnimListenerIfAlpha(final View v, Animation anim) {
+ if (v == null || anim == null) {
+ return;
+ }
+ if (shouldRunOnHWLayer(v, anim)) {
+ anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(v, anim));
+ }
+ }
+
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
@@ -881,7 +942,7 @@
case Fragment.INITIALIZING:
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
- f.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
+ f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mTarget = getFragment(f.mSavedFragmentState,
@@ -899,18 +960,18 @@
}
}
}
- f.mActivity = mActivity;
+ f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
- ? mParent.mChildFragmentManager : mActivity.mFragments;
+ ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
- f.onAttach(mActivity);
+ f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
- mActivity.onAttachFragment(f);
+ mHost.onAttachFragment(f);
}
if (!f.mRetaining) {
@@ -942,7 +1003,7 @@
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
- container = (ViewGroup)mContainer.findViewById(f.mContainerId);
+ container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
throwException(new IllegalArgumentException(
"No view found for id 0x"
@@ -965,6 +1026,7 @@
Animation anim = loadAnimation(f, transit, true,
transitionStyle);
if (anim != null) {
+ setHWLayerAnimListenerIfAlpha(f.mView, anim);
f.mView.startAnimation(anim);
}
container.addView(f.mView);
@@ -1021,7 +1083,7 @@
if (f.mView != null) {
// Need to save the current view state if not
// done already.
- if (!mActivity.isFinishing() && f.mSavedViewState == null) {
+ if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
saveFragmentViewState(f);
}
}
@@ -1036,21 +1098,18 @@
final Fragment fragment = f;
f.mAnimatingAway = f.mView;
f.mStateAfterAnimating = newState;
- anim.setAnimationListener(new AnimationListener() {
+ final View viewToAnimate = f.mView;
+ anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(
+ viewToAnimate, anim) {
@Override
public void onAnimationEnd(Animation animation) {
+ super.onAnimationEnd(animation);
if (fragment.mAnimatingAway != null) {
fragment.mAnimatingAway = null;
moveToState(fragment, fragment.mStateAfterAnimating,
0, 0, false);
}
}
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
- @Override
- public void onAnimationStart(Animation animation) {
- }
});
f.mView.startAnimation(anim);
}
@@ -1098,7 +1157,7 @@
if (!f.mRetaining) {
makeInactive(f);
} else {
- f.mActivity = null;
+ f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
f.mChildFragmentManager = null;
@@ -1121,8 +1180,8 @@
}
void moveToState(int newState, int transit, int transitStyle, boolean always) {
- if (mActivity == null && newState != Fragment.INITIALIZING) {
- throw new IllegalStateException("No activity");
+ if (mHost == null && newState != Fragment.INITIALIZING) {
+ throw new IllegalStateException("No host");
}
if (!always && mCurState == newState) {
@@ -1146,8 +1205,8 @@
startPendingDeferredFragments();
}
- if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
- mActivity.supportInvalidateOptionsMenu();
+ if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
+ mHost.onSupportInvalidateOptionsMenu();
mNeedMenuInvalidate = false;
}
}
@@ -1194,7 +1253,7 @@
mAvailIndices = new ArrayList<Integer>();
}
mAvailIndices.add(f.mIndex);
- mActivity.invalidateSupportFragment(f.mWho);
+ mHost.inactivateFragment(f.mWho);
f.initState();
}
@@ -1245,6 +1304,7 @@
Animation anim = loadAnimation(fragment, transition, false,
transitionStyle);
if (anim != null) {
+ setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
fragment.mView.startAnimation(anim);
}
fragment.mView.setVisibility(View.GONE);
@@ -1264,6 +1324,7 @@
Animation anim = loadAnimation(fragment, transition, true,
transitionStyle);
if (anim != null) {
+ setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
fragment.mView.startAnimation(anim);
}
fragment.mView.setVisibility(View.VISIBLE);
@@ -1395,7 +1456,7 @@
checkStateLoss();
}
synchronized (this) {
- if (mDestroyed || mActivity == null) {
+ if (mDestroyed || mHost == null) {
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
@@ -1403,8 +1464,8 @@
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
- mActivity.mHandler.removeCallbacks(mExecCommit);
- mActivity.mHandler.post(mExecCommit);
+ mHost.getHandler().removeCallbacks(mExecCommit);
+ mHost.getHandler().post(mExecCommit);
}
}
}
@@ -1473,7 +1534,7 @@
throw new IllegalStateException("Recursive entry to executePendingTransactions");
}
- if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
+ if (Looper.myLooper() != mHost.getHandler().getLooper()) {
throw new IllegalStateException("Must be called from main thread of process");
}
@@ -1493,7 +1554,7 @@
}
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
- mActivity.mHandler.removeCallbacks(mExecCommit);
+ mHost.getHandler().removeCallbacks(mExecCommit);
}
mExecutingActions = true;
@@ -1537,6 +1598,7 @@
reportBackStackChanged();
}
+ @SuppressWarnings("unused")
boolean popBackStackState(Handler handler, String name, int id, int flags) {
if (mBackStack == null) {
return false;
@@ -1780,7 +1842,7 @@
if (N > 0) {
backStack = new BackStackState[N];
for (int i=0; i<N; i++) {
- backStack[i] = new BackStackState(this, mBackStack.get(i));
+ backStack[i] = new BackStackState(mBackStack.get(i));
if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
+ ": " + mBackStack.get(i));
}
@@ -1794,7 +1856,7 @@
return fms;
}
- void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
+ void restoreAllState(Parcelable state, List<Fragment> nonConfig) {
// If there is no saved state at all, then there can not be
// any nonConfig fragments either, so that is that.
if (state == null) return;
@@ -1815,7 +1877,7 @@
f.mAdded = false;
f.mTarget = null;
if (fs.mSavedFragmentState != null) {
- fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
+ fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mSavedFragmentState = fs.mSavedFragmentState;
@@ -1832,7 +1894,7 @@
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
- Fragment f = fs.instantiate(mActivity, mParent);
+ Fragment f = fs.instantiate(mHost, mParent);
if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
mActive.add(f);
// Now that the fragment is instantiated (or came from being
@@ -1906,11 +1968,11 @@
mBackStack = null;
}
}
-
- public void attachActivity(FragmentActivity activity,
+
+ public void attachController(FragmentHostCallback host,
FragmentContainer container, Fragment parent) {
- if (mActivity != null) throw new IllegalStateException("Already attached");
- mActivity = activity;
+ if (mHost != null) throw new IllegalStateException("Already attached");
+ mHost = host;
mContainer = container;
mParent = parent;
}
@@ -1964,7 +2026,7 @@
mDestroyed = true;
execPendingActions();
moveToState(Fragment.INITIALIZING, false);
- mActivity = null;
+ mHost = null;
mContainer = null;
mParent = null;
}
@@ -2132,7 +2194,7 @@
String tag = a.getString(FragmentTag.Fragment_tag);
a.recycle();
- if (!Fragment.isSupportFragmentClass(mActivity, fname)) {
+ if (!Fragment.isSupportFragmentClass(mHost.getContext(), fname)) {
// Invalid support lib fragment; let the device's framework handle it.
// This will allow android.app.Fragments to do the right thing.
return null;
@@ -2166,7 +2228,7 @@
fragment.mTag = tag;
fragment.mInLayout = true;
fragment.mFragmentManager = this;
- fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState);
+ fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
addFragment(fragment, true);
} else if (fragment.mInLayout) {
@@ -2184,7 +2246,7 @@
// from last saved state), then give it the attributes to
// initialize itself.
if (!fragment.mRetaining) {
- fragment.onInflate(mActivity, attrs, fragment.mSavedFragmentState);
+ fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
}
}
diff --git a/v4/java/android/support/v4/app/LoaderManager.java b/v4/java/android/support/v4/app/LoaderManager.java
index 57c0a30..fad56e0 100644
--- a/v4/java/android/support/v4/app/LoaderManager.java
+++ b/v4/java/android/support/v4/app/LoaderManager.java
@@ -184,6 +184,9 @@
public boolean hasRunningLoaders() { return false; }
}
+/**
+ * @hide
+ */
class LoaderManagerImpl extends LoaderManager {
static final String TAG = "LoaderManager";
static boolean DEBUG = false;
@@ -201,14 +204,15 @@
final String mWho;
- FragmentActivity mActivity;
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;
boolean mCreatingLoader;
+ private FragmentHostCallback mHost;
- final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+ final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
+ Loader.OnLoadCanceledListener<Object> {
final int mId;
final Bundle mArgs;
LoaderManager.LoaderCallbacks<Object> mCallbacks;
@@ -216,8 +220,11 @@
boolean mHaveData;
boolean mDeliveredData;
Object mData;
+ @SuppressWarnings("hiding")
boolean mStarted;
+ @SuppressWarnings("hiding")
boolean mRetaining;
+ @SuppressWarnings("hiding")
boolean mRetainingStarted;
boolean mReportNextStart;
boolean mDestroyed;
@@ -260,6 +267,7 @@
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
+ mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
@@ -318,11 +326,21 @@
// Let the loader know we're done with it
mListenerRegistered = false;
mLoader.unregisterListener(this);
+ mLoader.unregisterOnLoadCanceledListener(this);
mLoader.stopLoading();
}
}
}
-
+
+ void cancel() {
+ if (DEBUG) Log.v(TAG, " Canceling: " + this);
+ if (mStarted && mLoader != null && mListenerRegistered) {
+ if (!mLoader.cancelLoad()) {
+ onLoadCanceled(mLoader);
+ }
+ }
+ }
+
void destroy() {
if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
@@ -331,15 +349,15 @@
if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
if (DEBUG) Log.v(TAG, " Reseting: " + this);
String lastBecause = null;
- if (mActivity != null) {
- lastBecause = mActivity.mFragments.mNoTransactionsBecause;
- mActivity.mFragments.mNoTransactionsBecause = "onLoaderReset";
+ if (mHost != null) {
+ lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
+ mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
}
try {
mCallbacks.onLoaderReset(mLoader);
} finally {
- if (mActivity != null) {
- mActivity.mFragments.mNoTransactionsBecause = lastBecause;
+ if (mHost != null) {
+ mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
}
@@ -350,6 +368,7 @@
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
+ mLoader.unregisterOnLoadCanceledListener(this);
}
mLoader.reset();
}
@@ -357,8 +376,38 @@
mPendingLoader.destroy();
}
}
-
- @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+
+ @Override
+ public void onLoadCanceled(Loader<Object> loader) {
+ if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);
+
+ if (mDestroyed) {
+ if (DEBUG) Log.v(TAG, " Ignoring load canceled -- destroyed");
+ return;
+ }
+
+ if (mLoaders.get(mId) != this) {
+ // This cancellation message is not coming from the current active loader.
+ // We don't care about it.
+ if (DEBUG) Log.v(TAG, " Ignoring load canceled -- not active");
+ return;
+ }
+
+ LoaderInfo pending = mPendingLoader;
+ if (pending != null) {
+ // There is a new request pending and we were just
+ // waiting for the old one to cancel or complete before starting
+ // it. So now it is time, switch over to the new loader.
+ if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
+ mPendingLoader = null;
+ mLoaders.put(mId, null);
+ destroy();
+ installLoader(pending);
+ }
+ }
+
+ @Override
+ public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
if (mDestroyed) {
@@ -409,25 +458,25 @@
mInactiveLoaders.remove(mId);
}
- if (mActivity != null && !hasRunningLoaders()) {
- mActivity.mFragments.startPendingDeferredFragments();
+ if (mHost != null && !hasRunningLoaders()) {
+ mHost.mFragmentManager.startPendingDeferredFragments();
}
}
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
- if (mActivity != null) {
- lastBecause = mActivity.mFragments.mNoTransactionsBecause;
- mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished";
+ if (mHost != null) {
+ lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
+ mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
mCallbacks.onLoadFinished(loader, data);
} finally {
- if (mActivity != null) {
- mActivity.mFragments.mNoTransactionsBecause = lastBecause;
+ if (mHost != null) {
+ mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
@@ -474,21 +523,21 @@
}
}
- LoaderManagerImpl(String who, FragmentActivity activity, boolean started) {
+ LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
mWho = who;
- mActivity = activity;
+ mHost = host;
mStarted = started;
}
- void updateActivity(FragmentActivity activity) {
- mActivity = activity;
+ void updateHostController(FragmentHostCallback host) {
+ mHost = host;
}
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
- LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
+ LoaderInfo info = new LoaderInfo(id, args, callback);
Loader<Object> loader = callback.onCreateLoader(id, args);
- info.mLoader = (Loader<Object>)loader;
+ info.mLoader = loader;
return info;
}
@@ -533,7 +582,7 @@
* @param id A unique (to this LoaderManager instance) identifier under
* which to manage the new Loader.
* @param args Optional arguments that will be propagated to
- * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}.
+ * {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}.
* @param callback Interface implementing management of this Loader. Required.
* Its onCreateLoader() method will be called while inside of the function to
* instantiate the Loader object.
@@ -583,7 +632,7 @@
* @param id A unique (to this LoaderManager instance) identifier under
* which to manage the new Loader.
* @param args Optional arguments that will be propagated to
- * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}.
+ * {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}.
* @param callback Interface implementing management of this Loader. Required.
* Its onCreateLoader() method will be called while inside of the function to
* instantiate the Loader object.
@@ -622,7 +671,9 @@
} else {
// Now we have three active loaders... we'll queue
// up this request to be processed once one of the other loaders
- // finishes.
+ // finishes or is canceled.
+ if (DEBUG) Log.v(TAG, " Current loader is running; attempting to cancel");
+ info.cancel();
if (info.mPendingLoader != null) {
if (DEBUG) Log.v(TAG, " Removing pending loader: " + info.mPendingLoader);
info.mPendingLoader.destroy();
@@ -672,8 +723,8 @@
mInactiveLoaders.removeAt(idx);
info.destroy();
}
- if (mActivity != null && !hasRunningLoaders()) {
- mActivity.mFragments.startPendingDeferredFragments();
+ if (mHost != null && !hasRunningLoaders()) {
+ mHost.mFragmentManager.startPendingDeferredFragments();
}
}
@@ -791,7 +842,7 @@
sb.append("LoaderManager{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" in ");
- DebugUtils.buildShortClassTag(mActivity, sb);
+ DebugUtils.buildShortClassTag(mHost, sb);
sb.append("}}");
return sb.toString();
}
diff --git a/v4/java/android/support/v4/app/NotificationCompat.java b/v4/java/android/support/v4/app/NotificationCompat.java
index 99c269e..b206e95 100644
--- a/v4/java/android/support/v4/app/NotificationCompat.java
+++ b/v4/java/android/support/v4/app/NotificationCompat.java
@@ -26,6 +26,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
+import android.support.annotation.ColorInt;
import android.support.v4.view.GravityCompat;
import android.view.Gravity;
import android.widget.RemoteViews;
@@ -342,6 +343,7 @@
* telling the system not to decorate this notification with any special color but instead use
* default colors when presenting this notification.
*/
+ @ColorInt
public static final int COLOR_DEFAULT = Color.TRANSPARENT;
/**
@@ -1198,7 +1200,7 @@
* rate. The rate is specified in terms of the number of milliseconds to be on
* and then the number of milliseconds to be off.
*/
- public Builder setLights(int argb, int onMs, int offMs) {
+ public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
mNotification.ledARGB = argb;
mNotification.ledOnMS = onMs;
mNotification.ledOffMS = offMs;
@@ -1504,7 +1506,7 @@
*
* @return The same Builder.
*/
- public Builder setColor(int argb) {
+ public Builder setColor(@ColorInt int argb) {
mColor = argb;
return this;
}
@@ -3012,7 +3014,7 @@
* automotive setting. This method can be used to override the color provided in the
* notification in such a situation.
*/
- public CarExtender setColor(int color) {
+ public CarExtender setColor(@ColorInt int color) {
mColor = color;
return this;
}
@@ -3022,6 +3024,7 @@
*
* @see setColor
*/
+ @ColorInt
public int getColor() {
return mColor;
}
diff --git a/v4/java/android/support/v4/app/SharedElementCallback.java b/v4/java/android/support/v4/app/SharedElementCallback.java
index 7c0de86..8beb29d 100644
--- a/v4/java/android/support/v4/app/SharedElementCallback.java
+++ b/v4/java/android/support/v4/app/SharedElementCallback.java
@@ -48,9 +48,23 @@
private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix";
/**
- * Called immediately after the start state is set for the shared element.
- * The shared element will start at the size and position of the shared element
- * in the launching Activity or Fragment.
+ * In Activity Transitions, onSharedElementStart is called immediately before
+ * capturing the start of the shared element state on enter and reenter transitions and
+ * immediately before capturing the end of the shared element state for exit and return
+ * transitions.
+ * <p>
+ * In Fragment Transitions, onSharedElementStart is called immediately before capturing the
+ * start state of all shared element transitions.
+ * <p>
+ * This call can be used to adjust the transition start state by modifying the shared
+ * element Views. Note that no layout step will be executed between onSharedElementStart
+ * and the transition state capture.
+ * <p>
+ * For Activity Transitions, any changes made in {@link #onSharedElementEnd(List, List, List)}
+ * that are not updated during layout should be corrected in onSharedElementStart for exit and
+ * return transitions. For example, rotation or scale will not be affected by layout and
+ * if changed in {@link #onSharedElementEnd(List, List, List)}, it will also have to be reset
+ * in onSharedElementStart again to correct the end state.
*
* @param sharedElementNames The names of the shared elements that were accepted into
* the View hierarchy.
@@ -65,17 +79,23 @@
List<View> sharedElements, List<View> sharedElementSnapshots) {}
/**
- * Called after the end state is set for the shared element, but before the end state
- * is captured by the shared element transition.
+ * In Activity Transitions, onSharedElementEnd is called immediately before
+ * capturing the end of the shared element state on enter and reenter transitions and
+ * immediately before capturing the start of the shared element state for exit and return
+ * transitions.
* <p>
- * Any customization done in
- * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)}
- * may need to be modified to the final state of the shared element if it is not
- * automatically corrected by layout. For example, rotation or scale will not
- * be affected by layout and if changed in {@link #onSharedElementStart(java.util.List,
- * java.util.List, java.util.List)}, it will also have to be set here again to correct
- * the end state.
- * </p>
+ * In Fragment Transitions, onSharedElementEnd is called immediately before capturing the
+ * end state of all shared element transitions.
+ * <p>
+ * This call can be used to adjust the transition end state by modifying the shared
+ * element Views. Note that no layout step will be executed between onSharedElementEnd
+ * and the transition state capture.
+ * <p>
+ * Any changes made in {@link #onSharedElementStart(List, List, List)} that are not updated
+ * during layout should be corrected in onSharedElementEnd. For example, rotation or scale
+ * will not be affected by layout and if changed in
+ * {@link #onSharedElementStart(List, List, List)}, it will also have to be reset in
+ * onSharedElementEnd again to correct the end state.
*
* @param sharedElementNames The names of the shared elements that were accepted into
* the View hierarchy.
diff --git a/v4/java/android/support/v4/content/AsyncTaskLoader.java b/v4/java/android/support/v4/content/AsyncTaskLoader.java
index 22fe3a2..17d7416 100644
--- a/v4/java/android/support/v4/content/AsyncTaskLoader.java
+++ b/v4/java/android/support/v4/content/AsyncTaskLoader.java
@@ -19,12 +19,14 @@
import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
+import android.support.v4.os.OperationCanceledException;
import android.support.v4.util.TimeUtils;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
/**
* Static library support version of the framework's {@link android.content.AsyncTaskLoader}.
@@ -38,19 +40,33 @@
static final boolean DEBUG = false;
final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable {
+ private final CountDownLatch mDone = new CountDownLatch(1);
- D result;
+ // Set to true to indicate that the task has been posted to a handler for
+ // execution at a later time. Used to throttle updates.
boolean waiting;
- private CountDownLatch done = new CountDownLatch(1);
-
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
- result = AsyncTaskLoader.this.onLoadInBackground();
- if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
- return result;
+ try {
+ D data = AsyncTaskLoader.this.onLoadInBackground();
+ if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
+ return data;
+ } catch (OperationCanceledException ex) {
+ if (!isCancelled()) {
+ // onLoadInBackground threw a canceled exception spuriously.
+ // This is problematic because it means that the LoaderManager did not
+ // cancel the Loader itself and still expects to receive a result.
+ // Additionally, the Loader's own state will not have been updated to
+ // reflect the fact that the task was being canceled.
+ // So we treat this case as an unhandled exception.
+ throw ex;
+ }
+ if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
+ return null;
+ }
}
/* Runs on the UI thread */
@@ -60,27 +76,41 @@
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
- done.countDown();
+ mDone.countDown();
}
}
+ /* Runs on the UI thread */
@Override
- protected void onCancelled() {
+ protected void onCancelled(D data) {
if (DEBUG) Log.v(TAG, this + " onCancelled");
try {
- AsyncTaskLoader.this.dispatchOnCancelled(this, result);
+ AsyncTaskLoader.this.dispatchOnCancelled(this, data);
} finally {
- done.countDown();
+ mDone.countDown();
}
}
+ /* Runs on the UI thread, when the waiting task is posted to a handler.
+ * This method is only executed when task execution was deferred (waiting was true). */
@Override
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}
+
+ /* Used for testing purposes to wait for the task to complete. */
+ public void waitForLoader() {
+ try {
+ mDone.await();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
}
+ private final Executor mExecutor;
+
volatile LoadTask mTask;
volatile LoadTask mCancellingTask;
@@ -89,12 +119,17 @@
Handler mHandler;
public AsyncTaskLoader(Context context) {
+ this(context, ModernAsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private AsyncTaskLoader(Context context, Executor executor) {
super(context);
+ mExecutor = executor;
}
/**
* Set amount to throttle updates by. This is the minimum time from
- * when the last {@link #onLoadInBackground()} call has completed until
+ * when the last {@link #loadInBackground()} call has completed until
* a new load is scheduled.
*
* @param delayMS Amount of delay, in milliseconds.
@@ -115,24 +150,9 @@
executePendingTask();
}
- /**
- * Attempt to cancel the current load task. See {@link android.os.AsyncTask#cancel(boolean)}
- * for more info. Must be called on the main thread of the process.
- *
- * <p>Cancelling is not an immediate operation, since the load is performed
- * in a background thread. If there is currently a load in progress, this
- * method requests that the load be cancelled, and notes this is the case;
- * once the background thread has completed its work its remaining state
- * will be cleared. If another load request comes in during this time,
- * it will be held until the cancelled load is complete.
- *
- * @return Returns <tt>false</tt> if the task could not be cancelled,
- * typically because it has already completed normally, or
- * because {@link #startLoading()} hasn't been called; returns
- * <tt>true</tt> otherwise.
- */
- public boolean cancelLoad() {
- if (DEBUG) Log.v(TAG, "cancelLoad: mTask=" + mTask);
+ @Override
+ protected boolean onCancelLoad() {
+ if (DEBUG) Log.v(TAG, "onCancelLoad: mTask=" + mTask);
if (mTask != null) {
if (mCancellingTask != null) {
// There was a pending task already waiting for a previous
@@ -158,6 +178,7 @@
if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled);
if (cancelled) {
mCancellingTask = mTask;
+ cancelLoadInBackground();
}
mTask = null;
return cancelled;
@@ -168,7 +189,10 @@
/**
* Called if the task was canceled before it was completed. Gives the class a chance
- * to properly dispose of the result.
+ * to clean up post-cancellation and to properly dispose of the result.
+ *
+ * @param data The value that was returned by {@link #loadInBackground}, or null
+ * if the task threw {@link OperationCanceledException}.
*/
public void onCanceled(D data) {
}
@@ -192,7 +216,7 @@
}
}
if (DEBUG) Log.v(TAG, "Executing: " + mTask);
- mTask.executeOnExecutor(ModernAsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ mTask.executeOnExecutor(mExecutor, (Void[]) null);
}
}
@@ -203,6 +227,8 @@
rollbackContentChanged();
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mCancellingTask = null;
+ if (DEBUG) Log.v(TAG, "Delivering cancellation");
+ deliverCancellation();
executePendingTask();
}
}
@@ -226,23 +252,76 @@
}
/**
+ * Called on a worker thread to perform the actual load and to return
+ * the result of the load operation.
+ *
+ * Implementations should not deliver the result directly, but should return them
+ * from this method, which will eventually end up calling {@link #deliverResult} on
+ * the UI thread. If implementations need to process the results on the UI thread
+ * they may override {@link #deliverResult} and do so there.
+ *
+ * To support cancellation, this method should periodically check the value of
+ * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
+ * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
+ * directly instead of polling {@link #isLoadInBackgroundCanceled}.
+ *
+ * When the load is canceled, this method may either return normally or throw
+ * {@link OperationCanceledException}. In either case, the {@link Loader} will
+ * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
+ * result object, if any.
+ *
+ * @return The result of the load operation.
+ *
+ * @throws OperationCanceledException if the load is canceled during execution.
+ *
+ * @see #isLoadInBackgroundCanceled
+ * @see #cancelLoadInBackground
+ * @see #onCanceled
*/
public abstract D loadInBackground();
/**
- * Called on a worker thread to perform the actual load. Implementations should not deliver the
- * result directly, but should return them from this method, which will eventually end up
- * calling {@link #deliverResult} on the UI thread. If implementations need to process
- * the results on the UI thread they may override {@link #deliverResult} and do so
- * there.
+ * Calls {@link #loadInBackground()}.
*
- * @return Implementations must return the result of their load operation.
+ * This method is reserved for use by the loader framework.
+ * Subclasses should override {@link #loadInBackground} instead of this method.
+ *
+ * @return The result of the load operation.
+ *
+ * @throws OperationCanceledException if the load is canceled during execution.
+ *
+ * @see #loadInBackground
*/
protected D onLoadInBackground() {
return loadInBackground();
}
/**
+ * Called on the main thread to abort a load in progress.
+ *
+ * Override this method to abort the current invocation of {@link #loadInBackground}
+ * that is running in the background on a worker thread.
+ *
+ * This method should do nothing if {@link #loadInBackground} has not started
+ * running or if it has already finished.
+ *
+ * @see #loadInBackground
+ */
+ public void cancelLoadInBackground() {
+ }
+
+ /**
+ * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
+ *
+ * @return True if the current invocation of {@link #loadInBackground} is being canceled.
+ *
+ * @see #loadInBackground
+ */
+ public boolean isLoadInBackgroundCanceled() {
+ return mCancellingTask != null;
+ }
+
+ /**
* Locks the current thread until the loader completes the current load
* operation. Returns immediately if there is no load operation running.
* Should not be called from the UI thread: calling it from the UI
@@ -255,11 +334,7 @@
public void waitForLoader() {
LoadTask task = mTask;
if (task != null) {
- try {
- task.done.await();
- } catch (InterruptedException e) {
- // Ignore
- }
+ task.waitForLoader();
}
}
diff --git a/v4/java/android/support/v4/content/ContentResolverCompat.java b/v4/java/android/support/v4/content/ContentResolverCompat.java
new file mode 100644
index 0000000..3b5f01c
--- /dev/null
+++ b/v4/java/android/support/v4/content/ContentResolverCompat.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.support.v4.os.CancellationSignal;
+import android.support.v4.os.OperationCanceledException;
+
+/**
+ * Helper for accessing features in {@link android.content.ContentResolver}
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class ContentResolverCompat {
+ interface ContentResolverCompatImpl {
+ Cursor query(ContentResolver resolver,
+ Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder, CancellationSignal cancellationSignal);
+ }
+
+ static class ContentResolverCompatImplBase implements ContentResolverCompatImpl {
+ @Override
+ public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ CancellationSignal cancellationSignal) {
+ // Note that the cancellation signal cannot cancel the query in progress
+ // prior to Jellybean so we cancel it preemptively here if needed.
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+ return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
+ }
+ }
+
+ static class ContentResolverCompatImplJB extends ContentResolverCompatImplBase {
+ @Override
+ public Cursor query(ContentResolver resolver, Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ CancellationSignal cancellationSignal) {
+ return ContentResolverCompatJellybean.query(resolver,
+ uri, projection, selection, selectionArgs, sortOrder,
+ cancellationSignal != null ?
+ cancellationSignal.getCancellationSignalObject() : null);
+ }
+ }
+
+ private static final ContentResolverCompatImpl IMPL;
+ static {
+ final int version = Build.VERSION.SDK_INT;
+ if (version >= 16) {
+ IMPL = new ContentResolverCompatImplJB();
+ } else {
+ IMPL = new ContentResolverCompatImplBase();
+ }
+ }
+
+ private ContentResolverCompat() {
+ /* Hide constructor */
+ }
+
+ /**
+ * Query the given URI, returning a {@link Cursor} over the result set
+ * with optional support for cancellation.
+ * <p>
+ * For best performance, the caller should follow these guidelines:
+ * <ul>
+ * <li>Provide an explicit projection, to prevent
+ * reading data from storage that aren't going to be used.</li>
+ * <li>Use question mark parameter markers such as 'phone=?' instead of
+ * explicit values in the {@code selection} parameter, so that queries
+ * that differ only by those values will be recognized as the same
+ * for caching purposes.</li>
+ * </ul>
+ * </p>
+ *
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param projection A list of which columns to return. Passing null will
+ * return all columns, which is inefficient.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null will
+ * return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A Cursor object, which is positioned before the first entry, or null
+ * @see Cursor
+ */
+ public static Cursor query(ContentResolver resolver,
+ Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder, CancellationSignal cancellationSignal) {
+ return IMPL.query(resolver, uri, projection, selection, selectionArgs,
+ sortOrder, cancellationSignal);
+ }
+}
diff --git a/v4/java/android/support/v4/content/ContextCompat.java b/v4/java/android/support/v4/content/ContextCompat.java
index 5c632dd..47baf8a 100644
--- a/v4/java/android/support/v4/content/ContextCompat.java
+++ b/v4/java/android/support/v4/content/ContextCompat.java
@@ -19,11 +19,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
-import android.os.StatFs;
+import android.os.Process;
+import android.support.annotation.NonNull;
import android.support.v4.os.EnvironmentCompat;
import android.util.Log;
@@ -95,7 +97,7 @@
* @param intents Array of intents defining the activities that will be started. The element
* length-1 will correspond to the top activity on the resulting task stack.
* @param options Additional options for how the Activity should be started.
- * See {@link android.content.Context#startActivity(Intent, Bundle)
+ * See {@link android.content.Context#startActivity(Intent, android.os.Bundle)
* @return true if the underlying API was available and the call was successful, false otherwise
*/
public static boolean startActivities(Context context, Intent[] intents,
@@ -133,7 +135,7 @@
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
- * most available space, as measured by {@link StatFs}.
+ * most available space, as measured by {@link android.os.StatFs}.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
@@ -192,7 +194,7 @@
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
- * most available space, as measured by {@link StatFs}.
+ * most available space, as measured by {@link android.os.StatFs}.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
@@ -252,7 +254,7 @@
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
- * most available space, as measured by {@link StatFs}.
+ * most available space, as measured by {@link android.os.StatFs}.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
@@ -323,6 +325,69 @@
}
/**
+ * Returns a color state list associated with a particular resource ID.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#MNC}, the returned
+ * color state list will be styled for the specified Context's theme.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @return A color state list, or {@code null} if the resource could not be
+ * resolved.
+ * @throws android.content.res.Resources.NotFoundException if the given ID
+ * does not exist.
+ */
+ public static final ColorStateList getColorStateList(Context context, int id) {
+ final int version = Build.VERSION.SDK_INT;
+ if (version >= 23) {
+ return ContextCompatApi23.getColorStateList(context, id);
+ } else {
+ return context.getResources().getColorStateList(id);
+ }
+ }
+
+ /**
+ * Returns a color associated with a particular resource ID
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#MNC}, the returned
+ * color will be styled for the specified Context's theme.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @return A single color value in the form 0xAARRGGBB.
+ * @throws android.content.res.Resources.NotFoundException if the given ID
+ * does not exist.
+ */
+ public static final int getColor(Context context, int id) {
+ final int version = Build.VERSION.SDK_INT;
+ if (version >= 23) {
+ return ContextCompatApi23.getColor(context, id);
+ } else {
+ return context.getResources().getColor(id);
+ }
+ }
+
+ /**
+ * Determine whether <em>you</em> have been granted a particular permission.
+ *
+ * @param permission The name of the permission being checked.
+ *
+ * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if you have the
+ * permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} if not.
+ *
+ * @see android.content.pm.PackageManager#checkPermission(String, String)
+ */
+ public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
+ if (permission == null) {
+ throw new IllegalArgumentException("permission is null");
+ }
+
+ return context.checkPermission(permission, android.os.Process.myPid(), Process.myUid());
+ }
+
+ /**
* Returns the absolute path to the directory on the filesystem similar to
* {@link Context#getFilesDir()}. The difference is that files placed under this
* directory will be excluded from automatic backup to remote storage on
diff --git a/v4/java/android/support/v4/content/CursorLoader.java b/v4/java/android/support/v4/content/CursorLoader.java
index 980e7d9..503bb9c 100644
--- a/v4/java/android/support/v4/content/CursorLoader.java
+++ b/v4/java/android/support/v4/content/CursorLoader.java
@@ -16,10 +16,12 @@
package android.support.v4.content;
+import android.content.ContentResolver;
import android.content.Context;
-import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.support.v4.os.CancellationSignal;
+import android.support.v4.os.OperationCanceledException;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -42,18 +44,48 @@
String mSortOrder;
Cursor mCursor;
+ CancellationSignal mCancellationSignal;
/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
- Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
- mSelectionArgs, mSortOrder);
- if (cursor != null) {
- // Ensure the cursor window is filled
- cursor.getCount();
- cursor.registerContentObserver(mObserver);
+ synchronized (this) {
+ if (isLoadInBackgroundCanceled()) {
+ throw new OperationCanceledException();
+ }
+ mCancellationSignal = new CancellationSignal();
}
- return cursor;
+ try {
+ Cursor cursor = ContentResolverCompat.query(getContext().getContentResolver(),
+ mUri, mProjection, mSelection, mSelectionArgs, mSortOrder,
+ mCancellationSignal);
+ if (cursor != null) {
+ try {
+ // Ensure the cursor window is filled.
+ cursor.getCount();
+ cursor.registerContentObserver(mObserver);
+ } catch (RuntimeException ex) {
+ cursor.close();
+ throw ex;
+ }
+ }
+ return cursor;
+ } finally {
+ synchronized (this) {
+ mCancellationSignal = null;
+ }
+ }
+ }
+
+ @Override
+ public void cancelLoadInBackground() {
+ super.cancelLoadInBackground();
+
+ synchronized (this) {
+ if (mCancellationSignal != null) {
+ mCancellationSignal.cancel();
+ }
+ }
}
/* Runs on the UI thread */
@@ -90,7 +122,7 @@
/**
* Creates a fully-specified CursorLoader. See
- * {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ * {@link ContentResolver#query(Uri, String[], String, String[], String)
* ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
diff --git a/v4/java/android/support/v4/content/Loader.java b/v4/java/android/support/v4/content/Loader.java
index bd01b0a..cf6cc99 100644
--- a/v4/java/android/support/v4/content/Loader.java
+++ b/v4/java/android/support/v4/content/Loader.java
@@ -34,6 +34,7 @@
public class Loader<D> {
int mId;
OnLoadCompleteListener<D> mListener;
+ OnLoadCanceledListener<D> mOnLoadCanceledListener;
Context mContext;
boolean mStarted = false;
boolean mAbandoned = false;
@@ -45,8 +46,8 @@
* An implementation of a ContentObserver that takes care of connecting
* it to the Loader to have the loader re-load its data when the observer
* is told it has changed. You do not normally need to use this yourself;
- * it is used for you by {@link android.support.v4.content.CursorLoader}
- * to take care of executing an update when the cursor's backing data changes.
+ * it is used for you by {@link CursorLoader} to take care of executing
+ * an update when the cursor's backing data changes.
*/
public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
@@ -83,8 +84,29 @@
}
/**
- * Stores away the application context associated with context. Since Loaders can be used
- * across multiple activities it's dangerous to store the context directly.
+ * Interface that is implemented to discover when a Loader has been canceled
+ * before it finished loading its data. You do not normally need to implement
+ * this yourself; it is used in the implementation of {@link android.support.v4.app.LoaderManager}
+ * to find out when a Loader it is managing has been canceled so that it
+ * can schedule the next Loader. This interface should only be used if a
+ * Loader is not being used in conjunction with LoaderManager.
+ */
+ public interface OnLoadCanceledListener<D> {
+ /**
+ * Called on the thread that created the Loader when the load is canceled.
+ *
+ * @param loader the loader that canceled the load
+ */
+ public void onLoadCanceled(Loader<D> loader);
+ }
+
+ /**
+ * Stores away the application context associated with context.
+ * Since Loaders can be used across multiple activities it's dangerous to
+ * store the context directly; always use {@link #getContext()} to retrieve
+ * the Loader's Context, don't use the constructor argument directly.
+ * The Context returned by {@link #getContext} is safe to use across
+ * Activity instances.
*
* @param context used to retrieve the application context.
*/
@@ -106,6 +128,18 @@
}
/**
+ * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
+ * Should only be called by subclasses.
+ *
+ * Must be called from the process's main thread.
+ */
+ public void deliverCancellation() {
+ if (mOnLoadCanceledListener != null) {
+ mOnLoadCanceledListener.onLoadCanceled(this);
+ }
+ }
+
+ /**
* @return an application context retrieved from the Context passed to the constructor.
*/
public Context getContext() {
@@ -150,6 +184,40 @@
}
/**
+ * Registers a listener that will receive callbacks when a load is canceled.
+ * The callback will be called on the process's main thread so it's safe to
+ * pass the results to widgets.
+ *
+ * Must be called from the process's main thread.
+ *
+ * @param listener The listener to register.
+ */
+ public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ if (mOnLoadCanceledListener != null) {
+ throw new IllegalStateException("There is already a listener registered");
+ }
+ mOnLoadCanceledListener = listener;
+ }
+
+ /**
+ * Unregisters a listener that was previously added with
+ * {@link #registerOnLoadCanceledListener}.
+ *
+ * Must be called from the process's main thread.
+ *
+ * @param listener The listener to unregister.
+ */
+ public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ if (mOnLoadCanceledListener == null) {
+ throw new IllegalStateException("No listener register");
+ }
+ if (mOnLoadCanceledListener != listener) {
+ throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+ }
+ mOnLoadCanceledListener = null;
+ }
+
+ /**
* Return whether this load has been started. That is, its {@link #startLoading()}
* has been called and no calls to {@link #stopLoading()} or
* {@link #reset()} have yet been made.
@@ -177,6 +245,12 @@
}
/**
+ * This function will normally be called for you automatically by
+ * {@link android.support.v4.app.LoaderManager} when the associated fragment/activity
+ * is being started. When using a Loader with {@link android.support.v4.app.LoaderManager},
+ * you <em>must not</em> call this method yourself, or you will conflict
+ * with its management of the Loader.
+ *
* Starts an asynchronous load of the Loader's data. When the result
* is ready the callbacks will be called on the process's main thread.
* If a previous load has been completed and is still valid
@@ -207,6 +281,43 @@
}
/**
+ * Attempt to cancel the current load task.
+ * Must be called on the main thread of the process.
+ *
+ * <p>Cancellation is not an immediate operation, since the load is performed
+ * in a background thread. If there is currently a load in progress, this
+ * method requests that the load be canceled, and notes this is the case;
+ * once the background thread has completed its work its remaining state
+ * will be cleared. If another load request comes in during this time,
+ * it will be held until the canceled load is complete.
+ *
+ * @return Returns <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called; returns
+ * <tt>true</tt> otherwise. When <tt>true</tt> is returned, the task
+ * is still running and the {@link OnLoadCanceledListener} will be called
+ * when the task completes.
+ */
+ public boolean cancelLoad() {
+ return onCancelLoad();
+ }
+
+ /**
+ * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
+ * This will always be called from the process's main thread.
+ *
+ * @return Returns <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called; returns
+ * <tt>true</tt> otherwise. When <tt>true</tt> is returned, the task
+ * is still running and the {@link OnLoadCanceledListener} will be called
+ * when the task completes.
+ */
+ protected boolean onCancelLoad() {
+ return false;
+ }
+
+ /**
* Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
* loaded data set and load a new one. This simply calls through to the
* implementation's {@link #onForceLoad()}. You generally should only call this
@@ -226,7 +337,13 @@
}
/**
- * Stops delivery of updates until the next time {@link #startLoading()} is called.
+ * This function will normally be called for you automatically by
+ * {@link android.support.v4.app.LoaderManager} when the associated fragment/activity
+ * is being stopped. When using a Loader with {@link android.support.v4.app.LoaderManager},
+ * you <em>must not</em> call this method yourself, or you will conflict
+ * with its management of the Loader.
+ *
+ * <p>Stops delivery of updates until the next time {@link #startLoading()} is called.
* Implementations should <em>not</em> invalidate their data at this point --
* clients are still free to use the last data the loader reported. They will,
* however, typically stop reporting new data if the data changes; they can
@@ -254,6 +371,12 @@
}
/**
+ * This function will normally be called for you automatically by
+ * {@link android.support.v4.app.LoaderManager} when restarting a Loader. When using
+ * a Loader with {@link android.support.v4.app.LoaderManager},
+ * you <em>must not</em> call this method yourself, or you will conflict
+ * with its management of the Loader.
+ *
* Tell the Loader that it is being abandoned. This is called prior
* to {@link #reset} to have it retain its current data but not report
* any new data.
@@ -272,10 +395,16 @@
* {@link #onReset()} happens. You can retrieve the current abandoned
* state with {@link #isAbandoned}.
*/
- protected void onAbandon() {
+ protected void onAbandon() {
}
/**
+ * This function will normally be called for you automatically by
+ * {@link android.support.v4.app.LoaderManager} when destroying a Loader. When using
+ * a Loader with {@link android.support.v4.app.LoaderManager},
+ * you <em>must not</em> call this method yourself, or you will conflict
+ * with its management of the Loader.
+ *
* Resets the state of the Loader. The Loader should at this point free
* all of its resources, since it may never be called again; however, its
* {@link #startLoading()} may later be called at which point it must be
diff --git a/v4/java/android/support/v4/content/ModernAsyncTask.java b/v4/java/android/support/v4/content/ModernAsyncTask.java
index 43b17f4..e76ca21 100644
--- a/v4/java/android/support/v4/content/ModernAsyncTask.java
+++ b/v4/java/android/support/v4/content/ModernAsyncTask.java
@@ -30,7 +30,9 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import android.os.AsyncTask;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.Process;
@@ -72,7 +74,7 @@
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
- private static final InternalHandler sHandler = new InternalHandler();
+ private static InternalHandler sHandler;
private static volatile Executor sDefaultExecutor = THREAD_POOL_EXECUTOR;
private final WorkerRunnable<Params, Result> mWorker;
@@ -101,9 +103,13 @@
FINISHED,
}
- /** @hide Used to force static handler to be created. */
- public static void init() {
- sHandler.getLooper();
+ private static Handler getHandler() {
+ synchronized (ModernAsyncTask.class) {
+ if (sHandler == null) {
+ sHandler = new InternalHandler();
+ }
+ return sHandler;
+ }
}
/** @hide */
@@ -134,13 +140,13 @@
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
- throw new RuntimeException("An error occured while executing doInBackground()",
- e.getCause());
+ throw new RuntimeException(
+ "An error occurred while executing doInBackground()", e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
} catch (Throwable t) {
- throw new RuntimeException("An error occured while executing "
- + "doInBackground()", t);
+ throw new RuntimeException(
+ "An error occurred while executing doInBackground()", t);
}
}
};
@@ -154,7 +160,7 @@
}
private Result postResult(Result result) {
- Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+ Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
@@ -449,7 +455,7 @@
*/
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
- sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+ getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
@@ -464,6 +470,10 @@
}
private static class InternalHandler extends Handler {
+ public InternalHandler() {
+ super(Looper.getMainLooper());
+ }
+
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
diff --git a/v4/java/android/support/v4/content/PermissionChecker.java b/v4/java/android/support/v4/content/PermissionChecker.java
new file mode 100644
index 0000000..1c864c4
--- /dev/null
+++ b/v4/java/android/support/v4/content/PermissionChecker.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Process;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.v4.app.AppOpsManagerCompat;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class provides permission check APIs that verify both the
+ * permission and the associated app op for this permission if
+ * such is defined.
+ * <p>
+ * In the new permission model permissions with protection level
+ * dangerous are runtime permissions. For apps targeting API MNC
+ * and above the user may not grant such permissions or revoke
+ * them at any time. For apps targeting API lower than MNC these
+ * permissions are always granted as such apps do not expect
+ * permission revocations and would crash. Therefore, when the
+ * user disables a permission for a legacy app in the UI the
+ * platform disables the APIs guarded by this permission making
+ * them a no-op which is doing nothing or returning an empty
+ * result or default error.
+ * </p>
+ * <p>
+ * It is important that when you perform an operation on behalf of
+ * another app you use these APIs to check for permissions as the
+ * app may be a legacy app that does not participate in the new
+ * permission model for which the user had disabled the "permission"
+ * which is achieved by disallowing the corresponding app op.
+ * </p>
+ */
+public final class PermissionChecker {
+ /** Permission result: The permission is granted. */
+ public static final int PERMISSION_GRANTED = PackageManager.PERMISSION_GRANTED;
+
+ /** Permission result: The permission is denied. */
+ public static final int PERMISSION_DENIED = PackageManager.PERMISSION_DENIED;
+
+ /** Permission result: The permission is denied because the app op is not allowed. */
+ public static final int PERMISSION_DENIED_APP_OP = PackageManager.PERMISSION_DENIED - 1;
+
+ @IntDef({PERMISSION_GRANTED,
+ PERMISSION_DENIED,
+ PERMISSION_DENIED_APP_OP})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionResult {}
+
+ private PermissionChecker() {
+ /* do nothing */
+ }
+
+ /**
+ * Checks whether a given package in a UID and PID has a given permission
+ * and whether the app op that corresponds to this permission is allowed.
+ *
+ * @param context Context for accessing resources.
+ * @param permission The permission to check.
+ * @param pid The process id for which to check.
+ * @param uid The uid for which to check.
+ * @param packageName The package name for which to check. If null the
+ * the first package for the calling UID will be used.
+ * @return The permission check result which is either {@link #PERMISSION_GRANTED}
+ * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
+ */
+ public static int checkPermission(@NonNull Context context, @NonNull String permission,
+ int pid, int uid, String packageName) {
+ if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
+ return PERMISSION_DENIED;
+ }
+
+ String op = AppOpsManagerCompat.permissionToOp(permission);
+ if (op == null) {
+ return PERMISSION_GRANTED;
+ }
+
+ if (packageName == null) {
+ String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
+ if (packageNames == null || packageNames.length <= 0) {
+ return PERMISSION_DENIED;
+ }
+ packageName = packageNames[0];
+ }
+
+ if (AppOpsManagerCompat.noteOp(context, op, uid, packageName)
+ != AppOpsManagerCompat.MODE_ALLOWED) {
+ return PERMISSION_DENIED_APP_OP;
+ }
+
+ return PERMISSION_GRANTED;
+ }
+
+ /**
+ * Checks whether your app has a given permission and whether the app op
+ * that corresponds to this permission is allowed.
+ *
+ * @param context Context for accessing resources.
+ * @param permission The permission to check.
+ * @return The permission check result which is either {@link #PERMISSION_GRANTED}
+ * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
+ */
+ public static int checkSelfPermission(@NonNull Context context,
+ @NonNull String permission) {
+ return checkPermission(context, permission, android.os.Process.myPid(),
+ android.os.Process.myUid(), context.getPackageName());
+ }
+
+ /**
+ * Checks whether the IPC you are handling has a given permission and whether
+ * the app op that corresponds to this permission is allowed.
+ *
+ * @param context Context for accessing resources.
+ * @param permission The permission to check.
+ * @param packageName The package name making the IPC. If null the
+ * the first package for the calling UID will be used.
+ * @return The permission check result which is either {@link #PERMISSION_GRANTED}
+ * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
+ */
+ public static int checkCallingPermission(@NonNull Context context,
+ @NonNull String permission, String packageName) {
+ if (Binder.getCallingPid() == Process.myPid()) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ return checkPermission(context, permission, android.os.Process.myPid(),
+ android.os.Process.myUid(), packageName);
+ }
+
+ /**
+ * Checks whether the IPC you are handling or your app has a given permission
+ * and whether the app op that corresponds to this permission is allowed.
+ *
+ * @param context Context for accessing resources.
+ * @param permission The permission to check.
+ * @return The permission check result which is either {@link #PERMISSION_GRANTED}
+ * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
+ */
+ public static int checkCallingOrSelfPermission(@NonNull Context context,
+ @NonNull String permission) {
+ String packageName = (Binder.getCallingPid() == Process.myPid())
+ ? context.getPackageName() : null;
+ return checkPermission(context, permission, Binder.getCallingPid(),
+ Binder.getCallingUid(), packageName);
+ }
+}
diff --git a/v4/java/android/support/v4/content/SharedPreferencesCompat.java b/v4/java/android/support/v4/content/SharedPreferencesCompat.java
new file mode 100644
index 0000000..dca99a8
--- /dev/null
+++ b/v4/java/android/support/v4/content/SharedPreferencesCompat.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.content;
+
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.support.annotation.NonNull;
+
+public class SharedPreferencesCompat {
+
+ public static class EditorCompat {
+
+ private static EditorCompat sInstance;
+
+ private interface Helper {
+ void apply(@NonNull SharedPreferences.Editor editor);
+ }
+
+ private static class EditorHelperBaseImpl implements Helper {
+
+ @Override
+ public void apply(@NonNull SharedPreferences.Editor editor) {
+ editor.commit();
+ }
+ }
+
+ private static class EditorHelperApi9Impl implements Helper {
+
+ @Override
+ public void apply(@NonNull SharedPreferences.Editor editor) {
+ EditorCompatGingerbread.apply(editor);
+ }
+ }
+
+ private final Helper mHelper;
+
+ private EditorCompat() {
+ if (Build.VERSION.SDK_INT >= 9) {
+ mHelper = new EditorHelperApi9Impl();
+ } else {
+ mHelper = new EditorHelperBaseImpl();
+ }
+ }
+
+ public static EditorCompat getInstance() {
+ if (sInstance == null) {
+ sInstance = new EditorCompat();
+ }
+ return sInstance;
+ }
+
+ public void apply(@NonNull SharedPreferences.Editor editor) {
+ mHelper.apply(editor);
+ }
+ }
+
+}
diff --git a/v4/java/android/support/v4/content/res/TypedArrayUtils.java b/v4/java/android/support/v4/content/res/TypedArrayUtils.java
new file mode 100644
index 0000000..79e4ac8
--- /dev/null
+++ b/v4/java/android/support/v4/content/res/TypedArrayUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.content.res;
+
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.AnyRes;
+import android.support.annotation.StyleableRes;
+
+/**
+ * Compat methods for accessing TypedArray values.
+ *
+ * @hide
+ */
+public class TypedArrayUtils {
+ public static boolean getBoolean(TypedArray a, @StyleableRes int index,
+ @StyleableRes int fallbackIndex, boolean defaultValue) {
+ boolean val = a.getBoolean(fallbackIndex, defaultValue);
+ return a.getBoolean(index, val);
+ }
+
+ public static Drawable getDrawable(TypedArray a, @StyleableRes int index,
+ @StyleableRes int fallbackIndex) {
+ Drawable val = a.getDrawable(index);
+ if (val == null) {
+ val = a.getDrawable(fallbackIndex);
+ }
+ return val;
+ }
+
+ public static int getInt(TypedArray a, @StyleableRes int index,
+ @StyleableRes int fallbackIndex, int defaultValue) {
+ int val = a.getInt(fallbackIndex, defaultValue);
+ return a.getInt(index, val);
+ }
+
+ public static @AnyRes int getResourceId(TypedArray a, @StyleableRes int index,
+ @StyleableRes int fallbackIndex, @AnyRes int defaultValue) {
+ int val = a.getResourceId(fallbackIndex, defaultValue);
+ return a.getResourceId(index, val);
+ }
+
+ public static String getString(TypedArray a, @StyleableRes int index,
+ @StyleableRes int fallbackIndex) {
+ String val = a.getString(index);
+ if (val == null) {
+ val = a.getString(fallbackIndex);
+ }
+ return val;
+ }
+
+ public static CharSequence[] getTextArray(TypedArray a, @StyleableRes int index,
+ @StyleableRes int fallbackIndex) {
+ CharSequence[] val = a.getTextArray(index);
+ if (val == null) {
+ val = a.getTextArray(fallbackIndex);
+ }
+ return val;
+ }
+}
diff --git a/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java b/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
index 99c762f..7d868b4 100644
--- a/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
+++ b/v4/java/android/support/v4/graphics/drawable/DrawableCompat.java
@@ -19,6 +19,7 @@
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.support.v4.view.ViewCompat;
/**
* Helper for accessing features in {@link android.graphics.drawable.Drawable}
@@ -38,6 +39,8 @@
void setTintList(Drawable drawable, ColorStateList tint);
void setTintMode(Drawable drawable, PorterDuff.Mode tintMode);
Drawable wrap(Drawable drawable);
+ void setLayoutDirection(Drawable drawable, int layoutDirection);
+ int getLayoutDirection(Drawable drawable);
}
/**
@@ -84,6 +87,16 @@
public Drawable wrap(Drawable drawable) {
return DrawableCompatBase.wrapForTinting(drawable);
}
+
+ @Override
+ public void setLayoutDirection(Drawable drawable, int layoutDirection) {
+ // No op for API < 23
+ }
+
+ @Override
+ public int getLayoutDirection(Drawable drawable) {
+ return ViewCompat.LAYOUT_DIRECTION_LTR;
+ }
}
/**
@@ -167,12 +180,29 @@
}
/**
+ * Interface implementation for devices with at least M APIs.
+ */
+ static class MDrawableImpl extends LollipopMr1DrawableImpl {
+ @Override
+ public void setLayoutDirection(Drawable drawable, int layoutDirection) {
+ DrawableCompatApi23.setLayoutDirection(drawable, layoutDirection);
+ }
+
+ @Override
+ public int getLayoutDirection(Drawable drawable) {
+ return DrawableCompatApi23.getLayoutDirection(drawable);
+ }
+ }
+
+ /**
* Select the correct implementation to use for the current platform.
*/
static final DrawableImpl IMPL;
static {
final int version = android.os.Build.VERSION.SDK_INT;
- if (version >= 22) {
+ if (version >= 23) {
+ IMPL = new MDrawableImpl();
+ } else if (version >= 22) {
IMPL = new LollipopMr1DrawableImpl();
} else if (version >= 21) {
IMPL = new LollipopDrawableImpl();
@@ -315,4 +345,29 @@
}
return (T) drawable;
}
+
+ /**
+ * Set the layout direction for this drawable. Should be a resolved
+ * layout direction, as the Drawable has no capacity to do the resolution on
+ * its own.
+ *
+ * @param layoutDirection the resolved layout direction for the drawable,
+ * either {@link ViewCompat#LAYOUT_DIRECTION_LTR}
+ * or {@link ViewCompat#LAYOUT_DIRECTION_RTL}
+ * @see #getLayoutDirection(Drawable)
+ */
+ public static void setLayoutDirection(Drawable drawable, int layoutDirection) {
+ IMPL.setLayoutDirection(drawable, layoutDirection);
+ }
+
+ /**
+ * Returns the resolved layout direction for this Drawable.
+ *
+ * @return One of {@link ViewCompat#LAYOUT_DIRECTION_LTR},
+ * {@link ViewCompat#LAYOUT_DIRECTION_RTL}
+ * @see #setLayoutDirection(Drawable, int)
+ */
+ public static int getLayoutDirection(Drawable drawable) {
+ return IMPL.getLayoutDirection(drawable);
+ }
}
diff --git a/v4/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java b/v4/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
new file mode 100644
index 0000000..0384f16
--- /dev/null
+++ b/v4/java/android/support/v4/hardware/fingerprint/FingerprintManagerCompat.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v4.hardware.fingerprint;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.CancellationSignal;
+
+import java.security.Signature;
+
+import javax.crypto.Cipher;
+
+/**
+ * A class that coordinates access to the fingerprint hardware.
+ * <p>
+ * On platforms before MNC, this class behaves as there would be no fingerprint hardware available.
+ */
+public class FingerprintManagerCompat {
+
+ private Context mContext;
+
+ /** Get a {@link FingerprintManagerCompat} instance for a provided context. */
+ public static FingerprintManagerCompat from(Context context) {
+ return new FingerprintManagerCompat(context);
+ }
+
+ private FingerprintManagerCompat(Context context) {
+ mContext = context;
+ }
+
+ static final FingerprintManagerCompatImpl IMPL;
+ static {
+ final int version = Build.VERSION.SDK_INT;
+ // STOPSHIP: Remove "MNC" check once the API's are final for MNC
+ if (version >= 23 || "MNC".equals(Build.VERSION.CODENAME)) {
+ IMPL = new Api23FingerprintManagerCompatImpl();
+ } else {
+ IMPL = new LegacyFingerprintManagerCompatImpl();
+ }
+ }
+
+ /**
+ * Determine if there is at least one fingerprint enrolled.
+ *
+ * @return true if at least one fingerprint is enrolled, false otherwise
+ */
+ public boolean hasEnrolledFingerprints() {
+ return IMPL.hasEnrolledFingerprints(mContext);
+ }
+
+ /**
+ * Determine if fingerprint hardware is present and functional.
+ *
+ * @return true if hardware is present and functional, false otherwise.
+ */
+ public boolean isHardwareDetected() {
+ return IMPL.isHardwareDetected(mContext);
+ }
+
+ /**
+ * Request authentication of a crypto object. This call warms up the fingerprint hardware
+ * and starts scanning for a fingerprint. It terminates when
+ * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ *
+ * @param crypto object associated with the call or null if none required.
+ * @param flags optional flags; should be 0
+ * @param cancel an object that can be used to cancel authentication
+ * @param callback an object to receive authentication events
+ * @param handler an optional handler for events
+ */
+ public void authenticate(@Nullable CryptoObject crypto, int flags,
+ @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback,
+ @Nullable Handler handler) {
+ IMPL.authenticate(mContext, crypto, flags, cancel, callback, handler);
+ }
+
+ /**
+ * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
+ * framework supports {@link Signature} and {@link Cipher} objects.
+ */
+ public static class CryptoObject {
+
+ private final Signature mSignature;
+ private final Cipher mCipher;
+
+ public CryptoObject(Signature signature) {
+ mSignature = signature;
+ mCipher = null;
+ }
+
+ public CryptoObject(Cipher cipher) {
+ mCipher = cipher;
+ mSignature = null;
+ }
+
+ /**
+ * Get {@link Signature} object.
+ * @return {@link Signature} object or null if this doesn't contain one.
+ */
+ public Signature getSignature() { return mSignature; }
+
+ /**
+ * Get {@link Cipher} object.
+ * @return {@link Cipher} object or null if this doesn't contain one.
+ */
+ public Cipher getCipher() { return mCipher; }
+ }
+
+ /**
+ * Container for callback data from {@link FingerprintManagerCompat#authenticate(CryptoObject,
+ * int, CancellationSignal, AuthenticationCallback, Handler)}.
+ */
+ public static final class AuthenticationResult {
+ private CryptoObject mCryptoObject;
+
+ public AuthenticationResult(CryptoObject crypto) {
+ mCryptoObject = crypto;
+ }
+
+ /**
+ * Obtain the crypto object associated with this transaction
+ * @return crypto object provided to {@link FingerprintManagerCompat#authenticate(
+ * CryptoObject, int, CancellationSignal, AuthenticationCallback, Handler)}.
+ */
+ public CryptoObject getCryptoObject() { return mCryptoObject; }
+ }
+
+ /**
+ * Callback structure provided to {@link FingerprintManagerCompat#authenticate(CryptoObject,
+ * int, CancellationSignal, AuthenticationCallback, Handler)}. Users of {@link
+ * FingerprintManagerCompat#authenticate(CryptoObject, int, CancellationSignal,
+ * AuthenticationCallback, Handler) } must provide an implementation of this for listening to
+ * fingerprint events.
+ */
+ public static abstract class AuthenticationCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ * @param errMsgId An integer identifying the error message
+ * @param errString A human-readable error string that can be shown in UI
+ */
+ public void onAuthenticationError(int errMsgId, CharSequence errString) { }
+
+ /**
+ * Called when a recoverable error has been encountered during authentication. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Sensor dirty, please clean it."
+ * @param helpMsgId An integer identifying the error message
+ * @param helpString A human-readable string that can be shown in UI
+ */
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { }
+
+ /**
+ * Called when a fingerprint is recognized.
+ * @param result An object containing authentication-related data
+ */
+ public void onAuthenticationSucceeded(AuthenticationResult result) { }
+
+ /**
+ * Called when a fingerprint is valid but not recognized.
+ */
+ public void onAuthenticationFailed() { }
+ }
+
+ private interface FingerprintManagerCompatImpl {
+ boolean hasEnrolledFingerprints(Context context);
+ boolean isHardwareDetected(Context context);
+ void authenticate(Context context, CryptoObject crypto, int flags,
+ CancellationSignal cancel, AuthenticationCallback callback, Handler handler);
+ }
+
+ private static class LegacyFingerprintManagerCompatImpl
+ implements FingerprintManagerCompatImpl {
+
+ public LegacyFingerprintManagerCompatImpl() {
+ }
+
+ @Override
+ public boolean hasEnrolledFingerprints(Context context) {
+ return false;
+ }
+
+ @Override
+ public boolean isHardwareDetected(Context context) {
+ return false;
+ }
+
+ @Override
+ public void authenticate(Context context, CryptoObject crypto, int flags,
+ CancellationSignal cancel, AuthenticationCallback callback, Handler handler) {
+ // TODO: Figure out behavior when there is no fingerprint hardware available
+ }
+ }
+
+ private static class Api23FingerprintManagerCompatImpl implements FingerprintManagerCompatImpl {
+
+ public Api23FingerprintManagerCompatImpl() {
+ }
+
+ @Override
+ public boolean hasEnrolledFingerprints(Context context) {
+ return FingerprintManagerCompatApi23.hasEnrolledFingerprints(context);
+ }
+
+ @Override
+ public boolean isHardwareDetected(Context context) {
+ return FingerprintManagerCompatApi23.isHardwareDetected(context);
+ }
+
+ @Override
+ public void authenticate(Context context, CryptoObject crypto, int flags,
+ CancellationSignal cancel, AuthenticationCallback callback, Handler handler) {
+ FingerprintManagerCompatApi23.authenticate(context, wrapCryptoObject(crypto), flags,
+ cancel != null ? cancel.getCancellationSignalObject() : null,
+ wrapCallback(callback), handler);
+ }
+
+ private static FingerprintManagerCompatApi23.CryptoObject wrapCryptoObject(
+ CryptoObject cryptoObject) {
+ if (cryptoObject == null) {
+ return null;
+ } else if (cryptoObject.getCipher() != null) {
+ return new FingerprintManagerCompatApi23.CryptoObject(cryptoObject.getCipher());
+ } else {
+ return new FingerprintManagerCompatApi23.CryptoObject(cryptoObject.getSignature());
+ }
+ }
+
+ private static CryptoObject unwrapCryptoObject(
+ FingerprintManagerCompatApi23.CryptoObject cryptoObject) {
+ if (cryptoObject == null) {
+ return null;
+ } else if (cryptoObject.getCipher() != null) {
+ return new CryptoObject(cryptoObject.getCipher());
+ } else {
+ return new CryptoObject(cryptoObject.getSignature());
+ }
+ }
+
+ private static FingerprintManagerCompatApi23.AuthenticationCallback wrapCallback(
+ final AuthenticationCallback callback) {
+ return new FingerprintManagerCompatApi23.AuthenticationCallback() {
+ @Override
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ callback.onAuthenticationError(errMsgId, errString);
+ }
+
+ @Override
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ callback.onAuthenticationHelp(helpMsgId, helpString);
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(
+ FingerprintManagerCompatApi23.AuthenticationResultInternal result) {
+ callback.onAuthenticationSucceeded(new AuthenticationResult(
+ unwrapCryptoObject(result.getCryptoObject())));
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ callback.onAuthenticationFailed();
+ }
+ };
+ }
+ }
+}
diff --git a/v4/java/android/support/v4/media/session/MediaSessionCompat.java b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
index fafb8e7..e6e2824 100644
--- a/v4/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -1786,10 +1786,10 @@
mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
break;
case MSG_ADJUST_VOLUME:
- adjustVolume((Integer) msg.obj, 0);
+ adjustVolume((int) msg.obj, 0);
break;
case MSG_SET_VOLUME:
- setVolumeTo((Integer) msg.obj, 0);
+ setVolumeTo((int) msg.obj, 0);
break;
}
}
diff --git a/v4/java/android/support/v4/os/CancellationSignal.java b/v4/java/android/support/v4/os/CancellationSignal.java
new file mode 100644
index 0000000..41bdfe6
--- /dev/null
+++ b/v4/java/android/support/v4/os/CancellationSignal.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.os;
+
+import android.os.Build;
+
+/**
+ * Static library support version of the framework's {@link android.os.CancellationSignal}.
+ * Used to write apps that run on platforms prior to Android 4.1. See the framework SDK
+ * documentation for a class overview.
+ */
+public final class CancellationSignal {
+ private boolean mIsCanceled;
+ private OnCancelListener mOnCancelListener;
+ private Object mCancellationSignalObj;
+ private boolean mCancelInProgress;
+
+ /**
+ * Creates a cancellation signal, initially not canceled.
+ */
+ public CancellationSignal() {
+ }
+
+ /**
+ * Returns true if the operation has been canceled.
+ *
+ * @return True if the operation has been canceled.
+ */
+ public boolean isCanceled() {
+ synchronized (this) {
+ return mIsCanceled;
+ }
+ }
+
+ /**
+ * Throws {@link OperationCanceledException} if the operation has been canceled.
+ *
+ * @throws OperationCanceledException if the operation has been canceled.
+ */
+ public void throwIfCanceled() {
+ if (isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ }
+
+ /**
+ * Cancels the operation and signals the cancellation listener.
+ * If the operation has not yet started, then it will be canceled as soon as it does.
+ */
+ public void cancel() {
+ final OnCancelListener listener;
+ final Object obj;
+ synchronized (this) {
+ if (mIsCanceled) {
+ return;
+ }
+ mIsCanceled = true;
+ mCancelInProgress = true;
+ listener = mOnCancelListener;
+ obj = mCancellationSignalObj;
+ }
+
+ try {
+ if (listener != null) {
+ listener.onCancel();
+ }
+ if (obj != null) {
+ CancellationSignalCompatJellybean.cancel(obj);
+ }
+ } finally {
+ synchronized (this) {
+ mCancelInProgress = false;
+ notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Sets the cancellation listener to be called when canceled.
+ *
+ * This method is intended to be used by the recipient of a cancellation signal
+ * such as a database or a content provider to handle cancellation requests
+ * while performing a long-running operation. This method is not intended to be
+ * used by applications themselves.
+ *
+ * If {@link CancellationSignal#cancel} has already been called, then the provided
+ * listener is invoked immediately.
+ *
+ * This method is guaranteed that the listener will not be called after it
+ * has been removed.
+ *
+ * @param listener The cancellation listener, or null to remove the current listener.
+ */
+ public void setOnCancelListener(OnCancelListener listener) {
+ synchronized (this) {
+ waitForCancelFinishedLocked();
+
+ if (mOnCancelListener == listener) {
+ return;
+ }
+ mOnCancelListener = listener;
+ if (!mIsCanceled || listener == null) {
+ return;
+ }
+ }
+ listener.onCancel();
+ }
+
+ /**
+ * Gets the framework {@link android.os.CancellationSignal} associated with this object.
+ * <p>
+ * Framework support for cancellation signals was added in
+ * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} so this method will always
+ * return null on older versions of the platform.
+ * </p>
+ *
+ * @return A framework cancellation signal object, or null on platform versions
+ * prior to Jellybean.
+ */
+ public Object getCancellationSignalObject() {
+ if (Build.VERSION.SDK_INT < 16) {
+ return null;
+ }
+ synchronized (this) {
+ if (mCancellationSignalObj == null) {
+ mCancellationSignalObj = CancellationSignalCompatJellybean.create();
+ if (mIsCanceled) {
+ CancellationSignalCompatJellybean.cancel(mCancellationSignalObj);
+ }
+ }
+ return mCancellationSignalObj;
+ }
+ }
+
+ private void waitForCancelFinishedLocked() {
+ while (mCancelInProgress) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+
+ /**
+ * Listens for cancellation.
+ */
+ public interface OnCancelListener {
+ /**
+ * Called when {@link CancellationSignal#cancel} is invoked.
+ */
+ void onCancel();
+ }
+}
diff --git a/v4/java/android/support/v4/os/OperationCanceledException.java b/v4/java/android/support/v4/os/OperationCanceledException.java
new file mode 100644
index 0000000..9b28030
--- /dev/null
+++ b/v4/java/android/support/v4/os/OperationCanceledException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.os;
+
+
+/**
+ * An exception type that is thrown when an operation in progress is canceled.
+ */
+public class OperationCanceledException extends RuntimeException {
+ public OperationCanceledException() {
+ this(null);
+ }
+
+ public OperationCanceledException(String message) {
+ super(message != null ? message : "The operation has been canceled.");
+ }
+}
diff --git a/v4/java/android/support/v4/text/ICUCompat.java b/v4/java/android/support/v4/text/ICUCompat.java
index 6df35ff..43ada52 100644
--- a/v4/java/android/support/v4/text/ICUCompat.java
+++ b/v4/java/android/support/v4/text/ICUCompat.java
@@ -18,34 +18,32 @@
import android.os.Build;
+import java.util.Locale;
+
public class ICUCompat {
interface ICUCompatImpl {
- public String getScript(String locale);
- public String addLikelySubtags(String locale);
+ public String maximizeAndGetScript(Locale locale);
}
static class ICUCompatImplBase implements ICUCompatImpl {
@Override
- public String getScript(String locale) {
+ public String maximizeAndGetScript(Locale locale) {
return null;
}
-
- @Override
- public String addLikelySubtags(String locale) {
- return locale;
- }
}
static class ICUCompatImplIcs implements ICUCompatImpl {
@Override
- public String getScript(String locale) {
- return ICUCompatIcs.getScript(locale);
+ public String maximizeAndGetScript(Locale locale) {
+ return ICUCompatIcs.maximizeAndGetScript(locale);
}
+ }
+ static class ICUCompatImplLollipop implements ICUCompatImpl {
@Override
- public String addLikelySubtags(String locale) {
- return ICUCompatIcs.addLikelySubtags(locale);
+ public String maximizeAndGetScript(Locale locale) {
+ return ICUCompatApi23.maximizeAndGetScript(locale);
}
}
@@ -53,7 +51,9 @@
static {
final int version = Build.VERSION.SDK_INT;
- if (version >= 14) {
+ if (version >= 21) {
+ IMPL = new ICUCompatImplLollipop();
+ } else if (version >= 14) {
IMPL = new ICUCompatImplIcs();
} else {
IMPL = new ICUCompatImplBase();
@@ -61,18 +61,11 @@
}
/**
- * Returns the script (language code) of a script.
+ * Returns the script for a given Locale.
*
- * @param locale The locale.
- * @return a String representing the script (language code) of the locale.
- */
- public static String getScript(String locale) {
- return IMPL.getScript(locale);
- }
-
- /**
- * Add the likely subtags for a provided locale ID, per the algorithm described in the following
- * CLDR technical report:
+ * If the locale isn't already in its maximal form, likely subtags for the provided locale
+ * ID are added before we determine the script. For further details, see the following CLDR
+ * technical report :
*
* http://www.unicode.org/reports/tr35/#Likely_Subtags
*
@@ -87,12 +80,10 @@
* "sr" maximizes to "sr_Cyrl_RS"
* "sh" maximizes to "sr_Latn_RS" (Note this will not reverse.)
* "zh_Hani" maximizes to "zh_Hans_CN" (Note this will not reverse.)
-
- * @param locale The locale to maximize
*
- * @return the maximized locale
+ * @return
*/
- public static String addLikelySubtags(String locale) {
- return IMPL.addLikelySubtags(locale);
+ public static String maximizeAndGetScript(Locale locale) {
+ return IMPL.maximizeAndGetScript(locale);
}
}
diff --git a/v4/java/android/support/v4/text/TextUtilsCompat.java b/v4/java/android/support/v4/text/TextUtilsCompat.java
index 436d72f..507a006 100644
--- a/v4/java/android/support/v4/text/TextUtilsCompat.java
+++ b/v4/java/android/support/v4/text/TextUtilsCompat.java
@@ -74,8 +74,7 @@
*/
public static int getLayoutDirectionFromLocale(@Nullable Locale locale) {
if (locale != null && !locale.equals(ROOT)) {
- final String scriptSubtag = ICUCompat.getScript(
- ICUCompat.addLikelySubtags(locale.toString()));
+ final String scriptSubtag = ICUCompat.maximizeAndGetScript(locale);
if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
diff --git a/v4/java/android/support/v4/util/CircularArray.java b/v4/java/android/support/v4/util/CircularArray.java
index 760c986..e2ac26b 100644
--- a/v4/java/android/support/v4/util/CircularArray.java
+++ b/v4/java/android/support/v4/util/CircularArray.java
@@ -93,7 +93,7 @@
/**
* Remove first element from front of the CircularArray and return it.
* @return The element removed.
- * @throws {@link ArrayIndexOutOfBoundsException} if CircularArray is empty.
+ * @throws ArrayIndexOutOfBoundsException if CircularArray is empty.
*/
public E popFirst() {
if (mHead == mTail) {
@@ -108,7 +108,7 @@
/**
* Remove last element from end of the CircularArray and return it.
* @return The element removed.
- * @throws {@link ArrayIndexOutOfBoundsException} if CircularArray is empty.
+ * @throws ArrayIndexOutOfBoundsException if CircularArray is empty.
*/
public E popLast() {
if (mHead == mTail) {
@@ -132,7 +132,7 @@
* Remove multiple elements from front of the CircularArray, ignore when numOfElements
* is less than or equals to 0.
* @param numOfElements Number of elements to remove.
- * @throws {@link ArrayIndexOutOfBoundsException} if numOfElements is larger than
+ * @throws ArrayIndexOutOfBoundsException if numOfElements is larger than
* {@link #size()}
*/
public void removeFromStart(int numOfElements) {
@@ -165,7 +165,7 @@
* Remove multiple elements from end of the CircularArray, ignore when numOfElements
* is less than or equals to 0.
* @param numOfElements Number of elements to remove.
- * @throws {@link ArrayIndexOutOfBoundsException} if numOfElements is larger than
+ * @throws ArrayIndexOutOfBoundsException if numOfElements is larger than
* {@link #size()}
*/
public void removeFromEnd(int numOfElements) {
diff --git a/v4/java/android/support/v4/util/CircularIntArray.java b/v4/java/android/support/v4/util/CircularIntArray.java
index 2389436..706d73b 100644
--- a/v4/java/android/support/v4/util/CircularIntArray.java
+++ b/v4/java/android/support/v4/util/CircularIntArray.java
@@ -94,7 +94,7 @@
/**
* Remove first integer from front of the CircularIntArray and return it.
* @return The integer removed.
- * @throws {@link ArrayIndexOutOfBoundsException} if CircularIntArray is empty.
+ * @throws ArrayIndexOutOfBoundsException if CircularIntArray is empty.
*/
public int popFirst() {
if (mHead == mTail) throw new ArrayIndexOutOfBoundsException();
@@ -106,7 +106,7 @@
/**
* Remove last integer from end of the CircularIntArray and return it.
* @return The integer removed.
- * @throws {@link ArrayIndexOutOfBoundsException} if CircularIntArray is empty.
+ * @throws ArrayIndexOutOfBoundsException if CircularIntArray is empty.
*/
public int popLast() {
if (mHead == mTail) throw new ArrayIndexOutOfBoundsException();
@@ -127,7 +127,7 @@
* Remove multiple integers from front of the CircularIntArray, ignore when numOfElements
* is less than or equals to 0.
* @param numOfElements Number of integers to remove.
- * @throws {@link ArrayIndexOutOfBoundsException} if numOfElements is larger than
+ * @throws ArrayIndexOutOfBoundsException if numOfElements is larger than
* {@link #size()}
*/
public void removeFromStart(int numOfElements) {
@@ -144,7 +144,7 @@
* Remove multiple elements from end of the CircularIntArray, ignore when numOfElements
* is less than or equals to 0.
* @param numOfElements Number of integers to remove.
- * @throws {@link ArrayIndexOutOfBoundsException} if numOfElements is larger than
+ * @throws ArrayIndexOutOfBoundsException if numOfElements is larger than
* {@link #size()}
*/
public void removeFromEnd(int numOfElements) {
diff --git a/v4/java/android/support/v4/view/PagerTabStrip.java b/v4/java/android/support/v4/view/PagerTabStrip.java
index 834035c..cd0206b 100644
--- a/v4/java/android/support/v4/view/PagerTabStrip.java
+++ b/v4/java/android/support/v4/view/PagerTabStrip.java
@@ -21,6 +21,7 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
@@ -127,7 +128,7 @@
*
* @param color Color to set as an 0xRRGGBB value. The high byte (alpha) is ignored.
*/
- public void setTabIndicatorColor(int color) {
+ public void setTabIndicatorColor(@ColorInt int color) {
mIndicatorColor = color;
mTabPaint.setColor(mIndicatorColor);
invalidate();
@@ -145,6 +146,7 @@
/**
* @return The current tab indicator color as an 0xRRGGBB value.
*/
+ @ColorInt
public int getTabIndicatorColor() {
return mIndicatorColor;
}
@@ -174,7 +176,7 @@
}
@Override
- public void setBackgroundColor(int color) {
+ public void setBackgroundColor(@ColorInt int color) {
super.setBackgroundColor(color);
if (!mDrawFullUnderlineSet) {
mDrawFullUnderline = (color & 0xFF000000) == 0;
diff --git a/v4/java/android/support/v4/view/PagerTitleStrip.java b/v4/java/android/support/v4/view/PagerTitleStrip.java
index 79c771f..cb9cd75 100644
--- a/v4/java/android/support/v4/view/PagerTitleStrip.java
+++ b/v4/java/android/support/v4/view/PagerTitleStrip.java
@@ -20,6 +20,8 @@
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.FloatRange;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -189,7 +191,7 @@
*
* @param alpha Opacity value in the range 0-1f
*/
- public void setNonPrimaryAlpha(float alpha) {
+ public void setNonPrimaryAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
mNonPrimaryAlpha = (int) (alpha * 255) & 0xFF;
final int transparentColor = (mNonPrimaryAlpha << 24) | (mTextColor & 0xFFFFFF);
mPrevText.setTextColor(transparentColor);
@@ -202,7 +204,7 @@
*
* @param color Color hex code in 0xAARRGGBB format
*/
- public void setTextColor(int color) {
+ public void setTextColor(@ColorInt int color) {
mTextColor = color;
mCurrText.setTextColor(color);
final int transparentColor = (mNonPrimaryAlpha << 24) | (mTextColor & 0xFFFFFF);
diff --git a/v4/java/android/support/v4/view/ViewCompat.java b/v4/java/android/support/v4/view/ViewCompat.java
index 57ac229..d3dce89 100644
--- a/v4/java/android/support/v4/view/ViewCompat.java
+++ b/v4/java/android/support/v4/view/ViewCompat.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.FloatRange;
import android.support.annotation.IdRes;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
@@ -355,6 +356,7 @@
public void requestApplyInsets(View view);
public void setChildrenDrawingOrderEnabled(ViewGroup viewGroup, boolean enabled);
public boolean getFitsSystemWindows(View view);
+ public boolean hasOverlappingRendering(View view);
void setFitsSystemWindows(View view, boolean fitSystemWindows);
void jumpDrawablesToCurrentState(View v);
void setOnApplyWindowInsetsListener(View view, OnApplyWindowInsetsListener listener);
@@ -581,6 +583,11 @@
}
}
+ @Override
+ public boolean hasOverlappingRendering(View view) {
+ return true;
+ }
+
private void bindTempDetach() {
try {
mDispatchStartTemporaryDetach = View.class.getDeclaredMethod(
@@ -1291,6 +1298,11 @@
public boolean getFitsSystemWindows(View view) {
return ViewCompatJB.getFitsSystemWindows(view);
}
+
+ @Override
+ public boolean hasOverlappingRendering(View view) {
+ return ViewCompatJB.hasOverlappingRendering(view);
+ }
}
static class JbMr1ViewCompatImpl extends JBViewCompatImpl {
@@ -2357,7 +2369,7 @@
*
* @param value The opacity of the view.
*/
- public static void setAlpha(View view, float value) {
+ public static void setAlpha(View view, @FloatRange(from=0.0, to=1.0) float value) {
IMPL.setAlpha(view, value);
}
@@ -2713,6 +2725,24 @@
}
/**
+ * Returns whether this View has content which overlaps.
+ *
+ * <p>This function, intended to be overridden by specific View types, is an optimization when
+ * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to
+ * an offscreen buffer and then composited into place, which can be expensive. If the view has
+ * no overlapping rendering, the view can draw each primitive with the appropriate alpha value
+ * directly. An example of overlapping rendering is a TextView with a background image, such as
+ * a Button. An example of non-overlapping rendering is a TextView with no background, or an
+ * ImageView with only the foreground image. The default implementation returns true; subclasses
+ * should override if they have cases which can be optimized.</p>
+ *
+ * @return true if the content in this view might overlap, false otherwise.
+ */
+ public static boolean hasOverlappingRendering(View view) {
+ return IMPL.hasOverlappingRendering(view);
+ }
+
+ /**
* Return if the padding as been set through relative values
* {@code View.setPaddingRelative(int, int, int, int)} or thru
*
diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java
index 57152c2..f19104a 100644
--- a/v4/java/android/support/v4/view/ViewPager.java
+++ b/v4/java/android/support/v4/view/ViewPager.java
@@ -28,6 +28,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.support.annotation.CallSuper;
import android.support.annotation.DrawableRes;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
@@ -1704,6 +1705,7 @@
* @param offset Value from [0, 1) indicating the offset from the page at position.
* @param offsetPixels Value in pixels indicating the offset from position.
*/
+ @CallSuper
protected void onPageScrolled(int position, float offset, int offsetPixels) {
// Offset any decor views if needed - keep them on-screen at all times.
if (mDecorChildCount > 0) {
diff --git a/v4/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java b/v4/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
index 1b239a7..cc6a8f7 100644
--- a/v4/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
+++ b/v4/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat;
import android.support.v4.view.ViewCompat;
+import android.text.InputType;
import android.view.View;
import java.util.ArrayList;
@@ -200,9 +201,12 @@
public Object getChild(Object info, int index);
public void addChild(Object info, View child);
public void addChild(Object info, View child, int virtualDescendantId);
+ public boolean removeChild(Object info, View child);
+ public boolean removeChild(Object info, View root, int virtualDescendantId);
public int getActions(Object info);
public void addAction(Object info, int action);
public void addAction(Object info, Object action);
+ public boolean removeAction(Object info, Object action);
public int getAccessibilityActionId(Object action);
public CharSequence getAccessibilityActionLabel(Object action);
public boolean performAction(Object info, int action);
@@ -259,6 +263,7 @@
public Object getCollectionItemInfo(Object info);
public void setCollectionItemInfo(Object info, Object collectionItemInfo);
public Object getRangeInfo(Object info);
+ public void setRangeInfo(Object info, Object rangeInfo);
public List<Object> getActionList(Object info);
public Object obtainCollectionInfo(int rowCount, int columnCount, boolean hierarchical,
int selectionMode);
@@ -273,10 +278,10 @@
public int getCollectionItemRowSpan(Object info);
public boolean isCollectionItemHeading(Object info);
public boolean isCollectionItemSelected(Object info);
- public AccessibilityNodeInfoCompat getTraversalBefore(Object info);
+ public Object getTraversalBefore(Object info);
public void setTraversalBefore(Object info, View view);
public void setTraversalBefore(Object info, View root, int virtualDescendantId);
- public AccessibilityNodeInfoCompat getTraversalAfter(Object info);
+ public Object getTraversalAfter(Object info);
public void setTraversalAfter(Object info, View view);
public void setTraversalAfter(Object info, View root, int virtualDescendantId);
public void setContentInvalid(Object info, boolean contentInvalid);
@@ -285,6 +290,29 @@
public CharSequence getError(Object info);
public void setLabelFor(Object info, View labeled);
public void setLabelFor(Object info, View root, int virtualDescendantId);
+ public Object getLabelFor(Object info);
+ public void setLabeledBy(Object info, View labeled);
+ public void setLabeledBy(Object info, View root, int virtualDescendantId);
+ public Object getLabeledBy(Object info);
+ public boolean canOpenPopup(Object info);
+ public void setCanOpenPopup(Object info, boolean opensPopup);
+ public List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId);
+ public Bundle getExtras(Object info);
+ public int getInputType(Object info);
+ public void setInputType(Object info, int inputType);
+ public void setMaxTextLength(Object info, int max);
+ public int getMaxTextLength(Object info);
+ public void setTextSelection(Object info, int start, int end);
+ public int getTextSelectionStart(Object info);
+ public int getTextSelectionEnd(Object info);
+ public Object getWindow(Object info);
+ public boolean isDismissable(Object info);
+ public void setDismissable(Object info, boolean dismissable);
+ public boolean isEditable(Object info);
+ public void setEditable(Object info, boolean editable);
+ public boolean isMultiLine(Object info);
+ public void setMultiLine(Object info, boolean multiLine);
+ public boolean refresh(Object info);
}
static class AccessibilityNodeInfoStubImpl implements AccessibilityNodeInfoImpl {
@@ -324,6 +352,11 @@
}
@Override
+ public boolean removeAction(Object info, Object action) {
+ return false;
+ }
+
+ @Override
public int getAccessibilityActionId(Object action) {
return 0;
}
@@ -344,6 +377,16 @@
}
@Override
+ public boolean removeChild(Object info, View child) {
+ return false;
+ }
+
+ @Override
+ public boolean removeChild(Object info, View root, int virtualDescendantId) {
+ return false;
+ }
+
+ @Override
public List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
return Collections.emptyList();
}
@@ -652,6 +695,10 @@
}
@Override
+ public void setRangeInfo(Object info, Object rangeInfo) {
+ }
+
+ @Override
public List<Object> getActionList(Object info) {
return null;
}
@@ -714,7 +761,7 @@
}
@Override
- public AccessibilityNodeInfoCompat getTraversalBefore(Object info) {
+ public Object getTraversalBefore(Object info) {
return null;
}
@@ -727,7 +774,7 @@
}
@Override
- public AccessibilityNodeInfoCompat getTraversalAfter(Object info) {
+ public Object getTraversalAfter(Object info) {
return null;
}
@@ -764,6 +811,112 @@
@Override
public void setLabelFor(Object info, View root, int virtualDescendantId) {
}
+
+ @Override
+ public Object getLabelFor(Object info) {
+ return null;
+ }
+
+ @Override
+ public void setLabeledBy(Object info, View labeled) {
+ }
+
+ @Override
+ public void setLabeledBy(Object info, View root, int virtualDescendantId) {
+ }
+
+ @Override
+ public Object getLabeledBy(Object info){
+ return null;
+ }
+
+ @Override
+ public boolean canOpenPopup(Object info) {
+ return false;
+ }
+
+ @Override
+ public void setCanOpenPopup(Object info, boolean opensPopup) {
+ }
+
+ @Override
+ public List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Bundle getExtras(Object info) {
+ return new Bundle();
+ }
+
+ @Override
+ public int getInputType(Object info) {
+ return InputType.TYPE_NULL;
+ }
+
+ @Override
+ public void setInputType(Object info, int inputType) {
+ }
+
+ @Override
+ public void setMaxTextLength(Object info, int max) {
+ }
+
+ @Override
+ public int getMaxTextLength(Object info) {
+ return -1;
+ }
+
+ @Override
+ public void setTextSelection(Object info, int start, int end) {
+ }
+
+ @Override
+ public int getTextSelectionStart(Object info) {
+ return -1;
+ }
+
+ @Override
+ public int getTextSelectionEnd(Object info) {
+ return -1;
+ }
+
+ @Override
+ public Object getWindow(Object info) {
+ return null;
+ }
+
+ @Override
+ public boolean isDismissable(Object info) {
+ return false;
+ }
+
+ @Override
+ public void setDismissable(Object info, boolean dismissable) {
+ }
+
+ @Override
+ public boolean isEditable(Object info) {
+ return false;
+ }
+
+ @Override
+ public void setEditable(Object info, boolean editable) {
+ }
+
+ @Override
+ public boolean isMultiLine(Object info) {
+ return false;
+ }
+
+ @Override
+ public void setMultiLine(Object info, boolean multiLine) {
+ }
+
+ @Override
+ public boolean refresh(Object info) {
+ return false;
+ }
}
static class AccessibilityNodeInfoIcsImpl extends AccessibilityNodeInfoStubImpl {
@@ -1070,7 +1223,41 @@
}
}
- static class AccessibilityNodeInfoJellybeanMr2Impl extends AccessibilityNodeInfoJellybeanImpl {
+ static class AccessibilityNodeInfoJellybeanMr1Impl extends AccessibilityNodeInfoJellybeanImpl {
+
+ @Override
+ public void setLabelFor(Object info, View labeled) {
+ AccessibilityNodeInfoCompatJellybeanMr1.setLabelFor(info, labeled);
+ }
+
+ @Override
+ public void setLabelFor(Object info, View root, int virtualDescendantId) {
+ AccessibilityNodeInfoCompatJellybeanMr1.setLabelFor(info, root, virtualDescendantId);
+ }
+
+ @Override
+ public Object getLabelFor(Object info) {
+ return AccessibilityNodeInfoCompatJellybeanMr1.getLabelFor(info);
+ }
+
+ @Override
+ public void setLabeledBy(Object info, View labeled) {
+ AccessibilityNodeInfoCompatJellybeanMr1.setLabeledBy(info, labeled);
+ }
+
+ @Override
+ public void setLabeledBy(Object info, View root, int virtualDescendantId) {
+ AccessibilityNodeInfoCompatJellybeanMr1.setLabeledBy(info, root, virtualDescendantId);
+ }
+
+ @Override
+ public Object getLabeledBy(Object info) {
+ return AccessibilityNodeInfoCompatJellybeanMr1.getLabeledBy(info);
+ }
+ }
+
+ static class AccessibilityNodeInfoJellybeanMr2Impl extends
+ AccessibilityNodeInfoJellybeanMr1Impl {
@Override
public String getViewIdResourceName(Object info) {
@@ -1081,6 +1268,42 @@
public void setViewIdResourceName(Object info, String viewId) {
AccessibilityNodeInfoCompatJellybeanMr2.setViewIdResourceName(info, viewId);
}
+
+ @Override
+ public List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId) {
+ return AccessibilityNodeInfoCompatJellybeanMr2.findAccessibilityNodeInfosByViewId(info,
+ viewId);
+ }
+
+ @Override
+ public void setTextSelection(Object info, int start, int end) {
+ AccessibilityNodeInfoCompatJellybeanMr2.setTextSelection(info, start, end);
+ }
+
+ @Override
+ public int getTextSelectionStart(Object info) {
+ return AccessibilityNodeInfoCompatJellybeanMr2.getTextSelectionStart(info);
+ }
+
+ @Override
+ public int getTextSelectionEnd(Object info) {
+ return AccessibilityNodeInfoCompatJellybeanMr2.getTextSelectionEnd(info);
+ }
+
+ @Override
+ public boolean isEditable(Object info) {
+ return AccessibilityNodeInfoCompatJellybeanMr2.isEditable(info);
+ }
+
+ @Override
+ public void setEditable(Object info, boolean editable) {
+ AccessibilityNodeInfoCompatJellybeanMr2.setEditable(info, editable);
+ }
+
+ @Override
+ public boolean refresh(Object info) {
+ return AccessibilityNodeInfoCompatJellybeanMr2.refresh(info);
+ }
}
static class AccessibilityNodeInfoKitKatImpl extends AccessibilityNodeInfoJellybeanMr2Impl {
@@ -1144,6 +1367,11 @@
}
@Override
+ public void setRangeInfo(Object info, Object rangeInfo) {
+ AccessibilityNodeInfoCompatKitKat.setRangeInfo(info, rangeInfo);
+ }
+
+ @Override
public int getCollectionItemColumnIndex(Object info) {
return AccessibilityNodeInfoCompatKitKat.CollectionItemInfo.getColumnIndex(info);
}
@@ -1182,6 +1410,51 @@
public boolean isContentInvalid(Object info) {
return AccessibilityNodeInfoCompatKitKat.isContentInvalid(info);
}
+
+ @Override
+ public boolean canOpenPopup(Object info) {
+ return AccessibilityNodeInfoCompatKitKat.canOpenPopup(info);
+ }
+
+ @Override
+ public void setCanOpenPopup(Object info, boolean opensPopup) {
+ AccessibilityNodeInfoCompatKitKat.setCanOpenPopup(info, opensPopup);
+ }
+
+ @Override
+ public Bundle getExtras(Object info) {
+ return AccessibilityNodeInfoCompatKitKat.getExtras(info);
+ }
+
+ @Override
+ public int getInputType(Object info) {
+ return AccessibilityNodeInfoCompatKitKat.getInputType(info);
+ }
+
+ @Override
+ public void setInputType(Object info, int inputType) {
+ AccessibilityNodeInfoCompatKitKat.setInputType(info, inputType);
+ }
+
+ @Override
+ public boolean isDismissable(Object info) {
+ return AccessibilityNodeInfoCompatKitKat.isDismissable(info);
+ }
+
+ @Override
+ public void setDismissable(Object info, boolean dismissable) {
+ AccessibilityNodeInfoCompatKitKat.setDismissable(info, dismissable);
+ }
+
+ @Override
+ public boolean isMultiLine(Object info) {
+ return AccessibilityNodeInfoCompatKitKat.isMultiLine(info);
+ }
+
+ @Override
+ public void setMultiLine(Object info, boolean multiLine) {
+ AccessibilityNodeInfoCompatKitKat.setMultiLine(info, multiLine);
+ }
}
static class AccessibilityNodeInfoApi21Impl extends AccessibilityNodeInfoKitKatImpl {
@@ -1208,6 +1481,11 @@
}
@Override
+ public boolean removeAction(Object info, Object action) {
+ return AccessibilityNodeInfoCompatApi21.removeAction(info, action);
+ }
+
+ @Override
public int getAccessibilityActionId(Object action) {
return AccessibilityNodeInfoCompatApi21.getAccessibilityActionId(action);
}
@@ -1240,25 +1518,35 @@
}
@Override
- public void setLabelFor(Object info, View labeled) {
- AccessibilityNodeInfoCompatApi21.setLabelFor(info, labeled);
+ public void setMaxTextLength(Object info, int max) {
+ AccessibilityNodeInfoCompatApi21.setMaxTextLength(info, max);
}
@Override
- public void setLabelFor(Object info, View root, int virtualDescendantId) {
- AccessibilityNodeInfoCompatApi21.setLabelFor(info, root, virtualDescendantId);
+ public int getMaxTextLength(Object info) {
+ return AccessibilityNodeInfoCompatApi21.getMaxTextLength(info);
+ }
+
+ @Override
+ public Object getWindow(Object info) {
+ return AccessibilityNodeInfoCompatApi21.getWindow(info);
+ }
+
+ @Override
+ public boolean removeChild(Object info, View child) {
+ return AccessibilityNodeInfoCompatApi21.removeChild(info, child);
+ }
+
+ @Override
+ public boolean removeChild(Object info, View root, int virtualDescendantId) {
+ return AccessibilityNodeInfoCompatApi21.removeChild(info, root, virtualDescendantId);
}
}
static class AccessibilityNodeInfoApi22Impl extends AccessibilityNodeInfoApi21Impl {
@Override
- public AccessibilityNodeInfoCompat getTraversalBefore(Object info) {
- Object nodeInfo = AccessibilityNodeInfoCompatApi22.getTraversalBefore(info);
- if (nodeInfo == null) {
- return null;
- }
-
- return new AccessibilityNodeInfoCompat(nodeInfo);
+ public Object getTraversalBefore(Object info) {
+ return AccessibilityNodeInfoCompatApi22.getTraversalBefore(info);
}
@Override
@@ -1272,13 +1560,8 @@
}
@Override
- public AccessibilityNodeInfoCompat getTraversalAfter(Object info) {
- Object nodeInfo = AccessibilityNodeInfoCompatApi22.getTraversalAfter(info);
- if (nodeInfo == null) {
- return null;
- }
-
- return new AccessibilityNodeInfoCompat(nodeInfo);
+ public Object getTraversalAfter(Object info) {
+ return AccessibilityNodeInfoCompatApi22.getTraversalAfter(info);
}
@Override
@@ -1301,6 +1584,8 @@
IMPL = new AccessibilityNodeInfoKitKatImpl();
} else if (Build.VERSION.SDK_INT >= 18) { // JellyBean MR2
IMPL = new AccessibilityNodeInfoJellybeanMr2Impl();
+ } else if (Build.VERSION.SDK_INT >= 17) { // JellyBean MR1
+ IMPL = new AccessibilityNodeInfoJellybeanMr1Impl();
} else if (Build.VERSION.SDK_INT >= 16) { // JellyBean
IMPL = new AccessibilityNodeInfoJellybeanImpl();
} else if (Build.VERSION.SDK_INT >= 14) { // ICS
@@ -1840,6 +2125,38 @@
}
/**
+ * Removes a child. If the child was not previously added to the node,
+ * calling this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param child The child.
+ * @return true if the child was present
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public boolean removeChild(View child) {
+ return IMPL.removeChild(mInfo, child);
+ }
+
+ /**
+ * Removes a virtual child which is a descendant of the given
+ * <code>root</code>. If the child was not previously added to the node,
+ * calling this method has no effect.
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual child.
+ * @return true if the child was present
+ * @see #addChild(View, int)
+ */
+ public boolean removeChild(View root, int virtualDescendantId) {
+ return IMPL.removeChild(mInfo, root, virtualDescendantId);
+ }
+
+ /**
* Gets the actions that can be performed on the node.
*
* @return The bit mask of with actions.
@@ -1883,6 +2200,24 @@
}
/**
+ * Removes an action that can be performed on the node. If the action was
+ * not already added to the node, calling this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param action The action to be removed.
+ * @return The action removed from the list of actions.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public boolean removeAction(AccessibilityActionCompat action) {
+ return IMPL.removeAction(mInfo, action.mAction);
+ }
+
+ /**
* Performs an action on the node.
* <p>
* <strong>Note:</strong> An action can be performed only if the request is
@@ -2574,6 +2909,20 @@
}
/**
+ * Sets the range info if this node is a range.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param rangeInfo The range info.
+ */
+ public void setRangeInfo(RangeInfoCompat rangeInfo) {
+ IMPL.setRangeInfo(mInfo, rangeInfo.mInfo);
+ }
+
+ /**
* Gets the actions that can be performed on the node.
*
* @return A list of AccessibilityActions.
@@ -2671,6 +3020,441 @@
IMPL.setLabelFor(mInfo, root, virtualDescendantId);
}
+ /**
+ * Gets the node info for which the view represented by this info serves as
+ * a label for accessibility purposes.
+ * <p>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfoCompat#recycle()}
+ * to avoid creating of multiple instances.
+ * </p>
+ *
+ * @return The labeled info.
+ */
+ public AccessibilityNodeInfoCompat getLabelFor() {
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getLabelFor(mInfo));
+ }
+
+ /**
+ * Sets the view which serves as the label of the view represented by
+ * this info for accessibility purposes.
+ *
+ * @param label The view that labels this node's source.
+ */
+ public void setLabeledBy(View label) {
+ IMPL.setLabeledBy(mInfo, label);
+ }
+
+ /**
+ * Sets the view which serves as the label of the view represented by
+ * this info for accessibility purposes. If <code>virtualDescendantId</code>
+ * is {@link View#NO_ID} the root is set as the label.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report themselves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root whose virtual descendant labels this node's source.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setLabeledBy(View root, int virtualDescendantId) {
+ IMPL.setLabeledBy(mInfo, root, virtualDescendantId);
+ }
+
+ /**
+ * Gets the node info which serves as the label of the view represented by
+ * this info for accessibility purposes.
+ * <p>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfoCompat#recycle()}
+ * to avoid creating of multiple instances.
+ * </p>
+ *
+ * @return The label.
+ */
+ public AccessibilityNodeInfoCompat getLabeledBy() {
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getLabeledBy(mInfo));
+ }
+
+ /**
+ * Gets if this node opens a popup or a dialog.
+ *
+ * @return If the the node opens a popup.
+ */
+ public boolean canOpenPopup() {
+ return IMPL.canOpenPopup(mInfo);
+ }
+
+ /**
+ * Sets if this node opens a popup or a dialog.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param opensPopup If the the node opens a popup.
+ */
+ public void setCanOpenPopup(boolean opensPopup) {
+ IMPL.setCanOpenPopup(mInfo, opensPopup);
+ }
+
+ /**
+ * Finds {@link AccessibilityNodeInfoCompat}s by the fully qualified view id's resource
+ * name where a fully qualified id is of the from "package:id/id_resource_name".
+ * For example, if the target application's package is "foo.bar" and the id
+ * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
+ *
+ * <p>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfoCompat#recycle()}
+ * to avoid creating of multiple instances.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> The primary usage of this API is for UI test automation
+ * and in order to report the fully qualified view id if an
+ * {@link AccessibilityNodeInfoCompat} the client has to set the
+ * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
+ * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
+ * </p>
+ *
+ * @param viewId The fully qualified resource name of the view id to find.
+ * @return A list of node info.
+ */
+ public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(String viewId) {
+ List<Object> nodes = IMPL.findAccessibilityNodeInfosByViewId(mInfo, viewId);
+ if (nodes != null) {
+ List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>();
+ for (Object node : nodes) {
+ result.add(new AccessibilityNodeInfoCompat(node));
+ }
+ return result;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Gets an optional bundle with extra data. The bundle
+ * is lazily created and never <code>null</code>.
+ * <p>
+ * <strong>Note:</strong> It is recommended to use the package
+ * name of your application as a prefix for the keys to avoid
+ * collisions which may confuse an accessibility service if the
+ * same key has different meaning when emitted from different
+ * applications.
+ * </p>
+ *
+ * @return The bundle.
+ */
+ public Bundle getExtras() {
+ return IMPL.getExtras(mInfo);
+ }
+
+ /**
+ * Gets the input type of the source as defined by {@link InputType}.
+ *
+ * @return The input type.
+ */
+ public int getInputType() {
+ return IMPL.getInputType(mInfo);
+ }
+
+ /**
+ * Sets the input type of the source as defined by {@link InputType}.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an
+ * AccessibilityService.
+ * </p>
+ *
+ * @param inputType The input type.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setInputType(int inputType) {
+ IMPL.setInputType(mInfo, inputType);
+ }
+
+ /**
+ * Sets the maximum text length, or -1 for no limit.
+ * <p>
+ * Typically used to indicate that an editable text field has a limit on
+ * the number of characters entered.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ *
+ * @param max The maximum text length.
+ * @see #getMaxTextLength()
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setMaxTextLength(int max) {
+ IMPL.setMaxTextLength(mInfo, max);
+ }
+
+ /**
+ * Returns the maximum text length for this node.
+ *
+ * @return The maximum text length, or -1 for no limit.
+ * @see #setMaxTextLength(int)
+ */
+ public int getMaxTextLength() {
+ return IMPL.getMaxTextLength(mInfo);
+ }
+
+ /**
+ * Sets the text selection start and end.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param start The text selection start.
+ * @param end The text selection end.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setTextSelection(int start, int end) {
+ IMPL.setTextSelection(mInfo, start, end);
+ }
+
+ /**
+ * Gets the text selection start.
+ *
+ * @return The text selection start if there is selection or -1.
+ */
+ public int getTextSelectionStart() {
+ return IMPL.getTextSelectionStart(mInfo);
+ }
+
+ /**
+ * Gets the text selection end.
+ *
+ * @return The text selection end if there is selection or -1.
+ */
+ public int getTextSelectionEnd() {
+ return IMPL.getTextSelectionEnd(mInfo);
+ }
+
+ /**
+ * Gets the node before which this one is visited during traversal. A screen-reader
+ * must visit the content of this node before the content of the one it precedes.
+ *
+ * @return The succeeding node if such or <code>null</code>.
+ *
+ * @see #setTraversalBefore(android.view.View)
+ * @see #setTraversalBefore(android.view.View, int)
+ */
+ public AccessibilityNodeInfoCompat getTraversalBefore() {
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getTraversalBefore(mInfo));
+ }
+
+ /**
+ * Sets the view before whose node this one should be visited during traversal. A
+ * screen-reader must visit the content of this node before the content of the one
+ * it precedes.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param view The view providing the preceding node.
+ *
+ * @see #getTraversalBefore()
+ */
+ public void setTraversalBefore(View view) {
+ IMPL.setTraversalBefore(mInfo, view);
+ }
+
+ /**
+ * Sets the node before which this one is visited during traversal. A screen-reader
+ * must visit the content of this node before the content of the one it precedes.
+ * The successor is a virtual descendant of the given <code>root</code>. If
+ * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
+ * as the successor.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report them selves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setTraversalBefore(View root, int virtualDescendantId) {
+ IMPL.setTraversalBefore(mInfo, root, virtualDescendantId);
+ }
+
+ /**
+ * Gets the node after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one.
+ *
+ * @return The succeeding node if such or <code>null</code>.
+ *
+ * @see #setTraversalAfter(android.view.View)
+ * @see #setTraversalAfter(android.view.View, int)
+ */
+ public AccessibilityNodeInfoCompat getTraversalAfter() {
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getTraversalAfter(mInfo));
+ }
+
+ /**
+ * Sets the view whose node is visited after this one in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param view The previous view.
+ *
+ * @see #getTraversalAfter()
+ */
+ public void setTraversalAfter(View view) {
+ IMPL.setTraversalAfter(mInfo, view);
+ }
+
+ /**
+ * Sets the node after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
+ * the root is set as the predecessor.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report them selves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setTraversalAfter(View root, int virtualDescendantId) {
+ IMPL.setTraversalAfter(mInfo, root, virtualDescendantId);
+ }
+
+ /**
+ * Gets the window to which this node belongs.
+ *
+ * @return The window.
+ *
+ * @see android.accessibilityservice.AccessibilityService#getWindows()
+ */
+ public AccessibilityWindowInfoCompat getWindow() {
+ return AccessibilityWindowInfoCompat.wrapNonNullInstance(IMPL.getWindow(mInfo));
+ }
+
+ /**
+ * Gets if the node can be dismissed.
+ *
+ * @return If the node can be dismissed.
+ */
+ public boolean isDismissable() {
+ return IMPL.isDismissable(mInfo);
+ }
+
+ /**
+ * Sets if the node can be dismissed.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param dismissable If the node can be dismissed.
+ */
+ public void setDismissable(boolean dismissable) {
+ IMPL.setDismissable(mInfo, dismissable);
+ }
+
+ /**
+ * Gets if the node is editable.
+ *
+ * @return True if the node is editable, false otherwise.
+ */
+ public boolean isEditable() {
+ return IMPL.isEditable(mInfo);
+ }
+
+ /**
+ * Sets whether this node is editable.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param editable True if the node is editable.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setEditable(boolean editable) {
+ IMPL.setEditable(mInfo, editable);
+ }
+
+ /**
+ * Gets if the node is a multi line editable text.
+ *
+ * @return True if the node is multi line.
+ */
+ public boolean isMultiLine() {
+ return IMPL.isMultiLine(mInfo);
+ }
+
+ /**
+ * Sets if the node is a multi line editable text.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param multiLine True if the node is multi line.
+ */
+ public void setMultiLine(boolean multiLine) {
+ IMPL.setMultiLine(mInfo, multiLine);
+ }
+
+ /**
+ * Refreshes this info with the latest state of the view it represents.
+ * <p>
+ * <strong>Note:</strong> If this method returns false this info is obsolete
+ * since it represents a view that is no longer in the view tree and should
+ * be recycled.
+ * </p>
+ * @return Whether the refresh succeeded.
+ */
+ public boolean refresh() {
+ return IMPL.refresh(mInfo);
+ }
+
@Override
public int hashCode() {
return (mInfo == null) ? 0 : mInfo.hashCode();
diff --git a/v4/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java b/v4/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
new file mode 100644
index 0000000..3197bb1
--- /dev/null
+++ b/v4/java/android/support/v4/view/accessibility/AccessibilityWindowInfoCompat.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view.accessibility;
+
+import android.graphics.Rect;
+import android.os.Build;
+
+/**
+ * Helper for accessing {@link android.view.accessibility.AccessibilityWindowInfo}
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class AccessibilityWindowInfoCompat {
+
+ private static interface AccessibilityWindowInfoImpl {
+ public Object obtain();
+ public Object obtain(Object info);
+ public int getType(Object info);
+ public int getLayer(Object info);
+ public Object getRoot(Object info);
+ public Object getParent(Object info);
+ public int getId(Object info);
+ public void getBoundsInScreen(Object info, Rect outBounds);
+ public boolean isActive(Object info);
+ public boolean isFocused(Object info);
+ public boolean isAccessibilityFocused(Object info);
+ public int getChildCount(Object info);
+ public Object getChild(Object info, int index);
+ public void recycle(Object info);
+ }
+
+ private static class AccessibilityWindowInfoStubImpl implements AccessibilityWindowInfoImpl {
+
+ @Override
+ public Object obtain() {
+ return null;
+ }
+
+ @Override
+ public Object obtain(Object info) {
+ return null;
+ }
+
+ @Override
+ public int getType(Object info) {
+ return UNDEFINED;
+ }
+
+ @Override
+ public int getLayer(Object info) {
+ return UNDEFINED;
+ }
+
+ @Override
+ public Object getRoot(Object info) {
+ return null;
+ }
+
+ @Override
+ public Object getParent(Object info) {
+ return null;
+ }
+
+ @Override
+ public int getId(Object info) {
+ return UNDEFINED;
+ }
+
+ @Override
+ public void getBoundsInScreen(Object info, Rect outBounds) {
+ }
+
+ @Override
+ public boolean isActive(Object info) {
+ return true;
+ }
+
+ @Override
+ public boolean isFocused(Object info) {
+ return true;
+ }
+
+ @Override
+ public boolean isAccessibilityFocused(Object info) {
+ return true;
+ }
+
+ @Override
+ public int getChildCount(Object info) {
+ return 0;
+ }
+
+ @Override
+ public Object getChild(Object info, int index) {
+ return null;
+ }
+
+ @Override
+ public void recycle(Object info) {
+ }
+ }
+
+ private static class AccessibilityWindowInfoApi21Impl extends AccessibilityWindowInfoStubImpl {
+ @Override
+ public Object obtain() {
+ return AccessibilityWindowInfoCompatApi21.obtain();
+ }
+
+ @Override
+ public Object obtain(Object info) {
+ return AccessibilityWindowInfoCompatApi21.obtain(info);
+ }
+
+ @Override
+ public int getType(Object info) {
+ return AccessibilityWindowInfoCompatApi21.getType(info);
+ }
+
+ @Override
+ public int getLayer(Object info) {
+ return AccessibilityWindowInfoCompatApi21.getLayer(info);
+ }
+
+ @Override
+ public Object getRoot(Object info) {
+ return AccessibilityWindowInfoCompatApi21.getRoot(info);
+ }
+
+ @Override
+ public Object getParent(Object info) {
+ return AccessibilityWindowInfoCompatApi21.getParent(info);
+ }
+
+ @Override
+ public int getId(Object info) {
+ return AccessibilityWindowInfoCompatApi21.getId(info);
+ }
+
+ @Override
+ public void getBoundsInScreen(Object info, Rect outBounds) {
+ AccessibilityWindowInfoCompatApi21.getBoundsInScreen(info, outBounds);
+ }
+
+ @Override
+ public boolean isActive(Object info) {
+ return AccessibilityWindowInfoCompatApi21.isActive(info);
+ }
+
+ @Override
+ public boolean isFocused(Object info) {
+ return AccessibilityWindowInfoCompatApi21.isFocused(info);
+ }
+
+ @Override
+ public boolean isAccessibilityFocused(Object info) {
+ return AccessibilityWindowInfoCompatApi21.isAccessibilityFocused(info);
+ }
+
+ @Override
+ public int getChildCount(Object info) {
+ return AccessibilityWindowInfoCompatApi21.getChildCount(info);
+ }
+
+ @Override
+ public Object getChild(Object info, int index) {
+ return AccessibilityWindowInfoCompatApi21.getChild(info, index);
+ }
+
+ @Override
+ public void recycle(Object info) {
+ AccessibilityWindowInfoCompatApi21.recycle(info);
+ }
+ }
+
+ static {
+ if (Build.VERSION.SDK_INT >= 21) {
+ IMPL = new AccessibilityWindowInfoApi21Impl();
+ } else {
+ IMPL = new AccessibilityWindowInfoStubImpl();
+ }
+ }
+
+ private static final AccessibilityWindowInfoImpl IMPL;
+ private Object mInfo;
+
+ private static final int UNDEFINED = -1;
+
+ /**
+ * Window type: This is an application window. Such a window shows UI for
+ * interacting with an application.
+ */
+ public static final int TYPE_APPLICATION = 1;
+
+ /**
+ * Window type: This is an input method window. Such a window shows UI for
+ * inputting text such as keyboard, suggestions, etc.
+ */
+ public static final int TYPE_INPUT_METHOD = 2;
+
+ /**
+ * Window type: This is an system window. Such a window shows UI for
+ * interacting with the system.
+ */
+ public static final int TYPE_SYSTEM = 3;
+
+ /**
+ * Window type: Windows that are overlaid <em>only</em> by an {@link
+ * android.accessibilityservice.AccessibilityService} for interception of
+ * user interactions without changing the windows an accessibility service
+ * can introspect. In particular, an accessibility service can introspect
+ * only windows that a sighted user can interact with which they can touch
+ * these windows or can type into these windows. For example, if there
+ * is a full screen accessibility overlay that is touchable, the windows
+ * below it will be introspectable by an accessibility service regardless
+ * they are covered by a touchable window.
+ */
+ public static final int TYPE_ACCESSIBILITY_OVERLAY = 4;
+
+ /**
+ * Creates a wrapper for info implementation.
+ *
+ * @param object The info to wrap.
+ * @return A wrapper for if the object is not null, null otherwise.
+ */
+ static AccessibilityWindowInfoCompat wrapNonNullInstance(Object object) {
+ if (object != null) {
+ return new AccessibilityWindowInfoCompat(object);
+ }
+ return null;
+ }
+
+ private AccessibilityWindowInfoCompat(Object info) {
+ mInfo = info;
+ }
+
+ /**
+ * Gets the type of the window.
+ *
+ * @return The type.
+ *
+ * @see #TYPE_APPLICATION
+ * @see #TYPE_INPUT_METHOD
+ * @see #TYPE_SYSTEM
+ * @see #TYPE_ACCESSIBILITY_OVERLAY
+ */
+ public int getType() {
+ return IMPL.getType(mInfo);
+ }
+
+ /**
+ * Gets the layer which determines the Z-order of the window. Windows
+ * with greater layer appear on top of windows with lesser layer.
+ *
+ * @return The window layer.
+ */
+ public int getLayer() {
+ return IMPL.getLayer(mInfo);
+ }
+
+ /**
+ * Gets the root node in the window's hierarchy.
+ *
+ * @return The root node.
+ */
+ public AccessibilityNodeInfoCompat getRoot() {
+ return AccessibilityNodeInfoCompat.wrapNonNullInstance(IMPL.getRoot(mInfo));
+ }
+
+ /**
+ * Gets the parent window if such.
+ *
+ * @return The parent window.
+ */
+ public AccessibilityWindowInfoCompat getParent() {
+ return wrapNonNullInstance(IMPL.getParent(mInfo));
+ }
+
+ /**
+ * Gets the unique window id.
+ *
+ * @return windowId The window id.
+ */
+ public int getId() {
+ return IMPL.getId(mInfo);
+ }
+
+ /**
+ * Gets the bounds of this window in the screen.
+ *
+ * @param outBounds The out window bounds.
+ */
+ public void getBoundsInScreen(Rect outBounds) {
+ IMPL.getBoundsInScreen(mInfo, outBounds);
+ }
+
+ /**
+ * Gets if this window is active. An active window is the one
+ * the user is currently touching or the window has input focus
+ * and the user is not touching any window.
+ *
+ * @return Whether this is the active window.
+ */
+ public boolean isActive() {
+ return IMPL.isActive(mInfo);
+ }
+
+ /**
+ * Gets if this window has input focus.
+ *
+ * @return Whether has input focus.
+ */
+ public boolean isFocused() {
+ return IMPL.isFocused(mInfo);
+ }
+
+ /**
+ * Gets if this window has accessibility focus.
+ *
+ * @return Whether has accessibility focus.
+ */
+ public boolean isAccessibilityFocused() {
+ return IMPL.isAccessibilityFocused(mInfo);
+ }
+
+ /**
+ * Gets the number of child windows.
+ *
+ * @return The child count.
+ */
+ public int getChildCount() {
+ return IMPL.getChildCount(mInfo);
+ }
+
+ /**
+ * Gets the child window at a given index.
+ *
+ * @param index The index.
+ * @return The child.
+ */
+ public AccessibilityWindowInfoCompat getChild(int index) {
+ return wrapNonNullInstance(IMPL.getChild(mInfo, index));
+ }
+
+ /**
+ * Returns a cached instance if such is available or a new one is
+ * created.
+ *
+ * @return An instance.
+ */
+ public static AccessibilityWindowInfoCompat obtain() {
+ return wrapNonNullInstance(IMPL.obtain());
+ }
+
+ /**
+ * Returns a cached instance if such is available or a new one is
+ * created. The returned instance is initialized from the given
+ * <code>info</code>.
+ *
+ * @param info The other info.
+ * @return An instance.
+ */
+ public static AccessibilityWindowInfoCompat obtain(AccessibilityWindowInfoCompat info) {
+ return wrapNonNullInstance(IMPL.obtain(info.mInfo));
+ }
+
+ /**
+ * Return an instance back to be reused.
+ * <p>
+ * <strong>Note:</strong> You must not touch the object after calling this function.
+ * </p>
+ *
+ * @throws IllegalStateException If the info is already recycled.
+ */
+ public void recycle() {
+ IMPL.recycle(mInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return (mInfo == null) ? 0 : mInfo.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AccessibilityWindowInfoCompat other = (AccessibilityWindowInfoCompat) obj;
+ if (mInfo == null) {
+ if (other.mInfo != null) {
+ return false;
+ }
+ } else if (!mInfo.equals(other.mInfo)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ Rect bounds = new Rect();
+ getBoundsInScreen(bounds);
+ builder.append("AccessibilityWindowInfo[");
+ builder.append("id=").append(getId());
+ builder.append(", type=").append(typeToString(getType()));
+ builder.append(", layer=").append(getLayer());
+ builder.append(", bounds=").append(bounds);
+ builder.append(", focused=").append(isFocused());
+ builder.append(", active=").append(isActive());
+ builder.append(", hasParent=").append(getParent() != null);
+ builder.append(", hasChildren=").append(getChildCount() > 0);
+ builder.append(']');
+ return builder.toString();
+ }
+
+ private static String typeToString(int type) {
+ switch (type) {
+ case TYPE_APPLICATION: {
+ return "TYPE_APPLICATION";
+ }
+ case TYPE_INPUT_METHOD: {
+ return "TYPE_INPUT_METHOD";
+ }
+ case TYPE_SYSTEM: {
+ return "TYPE_SYSTEM";
+ }
+ case TYPE_ACCESSIBILITY_OVERLAY: {
+ return "TYPE_ACCESSIBILITY_OVERLAY";
+ }
+ default:
+ return "<UNKNOWN>";
+ }
+ }
+}
diff --git a/v4/java/android/support/v4/widget/CompoundButtonCompat.java b/v4/java/android/support/v4/widget/CompoundButtonCompat.java
new file mode 100644
index 0000000..d08d1c0
--- /dev/null
+++ b/v4/java/android/support/v4/widget/CompoundButtonCompat.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Canvas;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.widget.CompoundButton;
+
+/**
+ * Helper for accessing {@link android.widget.CompoundButton} methods introduced after
+ * API level 4 in a backwards compatible fashion.
+ */
+public final class CompoundButtonCompat {
+
+ private static final CompoundButtonCompatImpl IMPL;
+
+ static {
+ final int sdk = Build.VERSION.SDK_INT;
+ if (sdk >= 23 || "MNC".equals(Build.VERSION.CODENAME)) {
+ IMPL = new Api23CompoundButtonImpl();
+ } else if (sdk >= 21) {
+ IMPL = new LollipopCompoundButtonImpl();
+ } else {
+ IMPL = new BaseCompoundButtonCompat();
+ }
+ }
+
+ interface CompoundButtonCompatImpl {
+ void setButtonTintList(CompoundButton button, ColorStateList tint);
+ ColorStateList getButtonTintList(CompoundButton button);
+ void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode);
+ PorterDuff.Mode getButtonTintMode(CompoundButton button);
+ Drawable getButtonDrawable(CompoundButton button);
+ }
+
+ static class BaseCompoundButtonCompat implements CompoundButtonCompatImpl {
+ @Override
+ public void setButtonTintList(CompoundButton button, ColorStateList tint) {
+ CompoundButtonCompatDonut.setButtonTintList(button, tint);
+ }
+
+ @Override
+ public ColorStateList getButtonTintList(CompoundButton button) {
+ return CompoundButtonCompatDonut.getButtonTintList(button);
+ }
+
+ @Override
+ public void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
+ CompoundButtonCompatDonut.setButtonTintMode(button, tintMode);
+ }
+
+ @Override
+ public PorterDuff.Mode getButtonTintMode(CompoundButton button) {
+ return CompoundButtonCompatDonut.getButtonTintMode(button);
+ }
+
+ @Override
+ public Drawable getButtonDrawable(CompoundButton button) {
+ return CompoundButtonCompatDonut.getButtonDrawable(button);
+ }
+ }
+
+ static class LollipopCompoundButtonImpl extends BaseCompoundButtonCompat {
+ @Override
+ public void setButtonTintList(CompoundButton button, ColorStateList tint) {
+ CompoundButtonCompatLollipop.setButtonTintList(button, tint);
+ }
+
+ @Override
+ public ColorStateList getButtonTintList(CompoundButton button) {
+ return CompoundButtonCompatLollipop.getButtonTintList(button);
+ }
+
+ @Override
+ public void setButtonTintMode(CompoundButton button, PorterDuff.Mode tintMode) {
+ CompoundButtonCompatLollipop.setButtonTintMode(button, tintMode);
+ }
+
+ @Override
+ public PorterDuff.Mode getButtonTintMode(CompoundButton button) {
+ return CompoundButtonCompatLollipop.getButtonTintMode(button);
+ }
+ }
+
+ static class Api23CompoundButtonImpl extends LollipopCompoundButtonImpl {
+ @Override
+ public Drawable getButtonDrawable(CompoundButton button) {
+ return CompoundButtonCompatApi23.getButtonDrawable(button);
+ }
+ }
+
+ private CompoundButtonCompat() {}
+
+ /**
+ * Applies a tint to the button drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+ * <p>
+ * Subsequent calls to {@link CompoundButton#setButtonDrawable(Drawable)} should
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using {@link DrawableCompat#setTintList(Drawable, ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @see #setButtonTintList(CompoundButton, ColorStateList)
+ */
+ public static void setButtonTintList(@NonNull CompoundButton button, @Nullable ColorStateList tint) {
+ IMPL.setButtonTintList(button, tint);
+ }
+
+ /**
+ * Returns the tint applied to the button drawable
+ *
+ * @see #setButtonTintList(CompoundButton, ColorStateList)
+ */
+ @Nullable
+ public static ColorStateList getButtonTintList(@NonNull CompoundButton button) {
+ return IMPL.getButtonTintList(button);
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setButtonTintList(CompoundButton, ColorStateList)}} to the button drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_IN}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @see #getButtonTintMode(CompoundButton)
+ * @see DrawableCompat#setTintMode(Drawable, PorterDuff.Mode)
+ */
+ public static void setButtonTintMode(@NonNull CompoundButton button,
+ @Nullable PorterDuff.Mode tintMode) {
+ IMPL.setButtonTintMode(button, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTintMode(PorterDuff.Mode)
+ */
+ @Nullable
+ public static PorterDuff.Mode getButtonTintMode(@NonNull CompoundButton button) {
+ return IMPL.getButtonTintMode(button);
+ }
+
+ /**
+ * Returns the drawable used as the compound button image
+ *
+ * @see CompoundButton#setButtonDrawable(Drawable)
+ */
+ @Nullable
+ public static Drawable getButtonDrawable(@NonNull CompoundButton button) {
+ return IMPL.getButtonDrawable(button);
+ }
+}
diff --git a/v4/java/android/support/v4/widget/DrawerLayout.java b/v4/java/android/support/v4/widget/DrawerLayout.java
index a8967a2..b68bc28 100644
--- a/v4/java/android/support/v4/widget/DrawerLayout.java
+++ b/v4/java/android/support/v4/widget/DrawerLayout.java
@@ -29,10 +29,12 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.KeyEventCompat;
@@ -134,6 +136,7 @@
private static final int MIN_DRAWER_MARGIN = 64; // dp
+ private static final int DRAWER_ELEVATION = 10; //dp
private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
@@ -163,8 +166,13 @@
/** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
private static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
+ /** Whether the drawer shadow comes from setting elevation on the drawer. */
+ private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
+ Build.VERSION.SDK_INT >= 21;
+
private final ChildAccessibilityDelegate mChildAccessibilityDelegate =
new ChildAccessibilityDelegate();
+ private float mDrawerElevation;
private int mMinDrawerMargin;
@@ -189,9 +197,9 @@
private float mInitialMotionX;
private float mInitialMotionY;
- private Drawable mShadowLeft;
- private Drawable mShadowRight;
private Drawable mStatusBarBackground;
+ private Drawable mShadowLeftResolved;
+ private Drawable mShadowRightResolved;
private CharSequence mTitleLeft;
private CharSequence mTitleRight;
@@ -199,6 +207,12 @@
private Object mLastInsets;
private boolean mDrawStatusBarBackground;
+ /** Shadow drawables for different gravity */
+ private Drawable mShadowStart = null;
+ private Drawable mShadowEnd = null;
+ private Drawable mShadowLeft = null;
+ private Drawable mShadowRight = null;
+
/**
* Listener for monitoring events about drawers.
*/
@@ -361,6 +375,38 @@
IMPL.configureApplyInsets(this);
mStatusBarBackground = IMPL.getDefaultStatusBarBackground(context);
}
+
+ mDrawerElevation = DRAWER_ELEVATION * density;
+ }
+
+ /**
+ * Sets the base elevation of the drawer(s) relative to the parent, in pixels. Note that the
+ * elevation change is only supported in API 21 and above.
+ *
+ * @param elevation The base depth position of the view, in pixels.
+ */
+ public void setDrawerElevation(float elevation) {
+ mDrawerElevation = elevation;
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (isDrawerView(child)) {
+ ViewCompat.setElevation(child, mDrawerElevation);
+ }
+ }
+ }
+
+ /**
+ * The base elevation of the drawer(s) relative to the parent, in pixels. Note that the
+ * elevation change is only supported in API 21 and above. For unsupported API levels, 0 will
+ * be returned as the elevation.
+ *
+ * @return The base depth position of the view, in pixels.
+ */
+ public float getDrawerElevation() {
+ if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+ return mDrawerElevation;
+ }
+ return 0f;
}
/**
@@ -376,8 +422,15 @@
}
/**
- * Set a simple drawable used for the left or right shadow.
- * The drawable provided must have a nonzero intrinsic width.
+ * Set a simple drawable used for the left or right shadow. The drawable provided must have a
+ * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
+ * instead of the drawable provided.
+ *
+ * <p>Note that for better support for both left-to-right and right-to-left layout
+ * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
+ * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
+ * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
+ * auto-mirrored such that the drawable will be mirrored in RTL layout.</p>
*
* @param shadowDrawable Shadow drawable to use at the edge of a drawer
* @param gravity Which drawer the shadow should apply to
@@ -388,22 +441,35 @@
* They're probably nuts, but we might want to consider registering callbacks,
* setting states, etc. properly.
*/
-
- final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
- ViewCompat.getLayoutDirection(this));
- if ((absGravity & Gravity.LEFT) == Gravity.LEFT) {
+ if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+ // No op. Drawer shadow will come from setting an elevation on the drawer.
+ return;
+ }
+ if ((gravity & GravityCompat.START) == GravityCompat.START) {
+ mShadowStart = shadowDrawable;
+ } else if ((gravity & GravityCompat.END) == GravityCompat.END) {
+ mShadowEnd = shadowDrawable;
+ } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
mShadowLeft = shadowDrawable;
- invalidate();
- }
- if ((absGravity & Gravity.RIGHT) == Gravity.RIGHT) {
+ } else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
mShadowRight = shadowDrawable;
- invalidate();
+ } else {
+ return;
}
+ resolveShadowDrawables();
+ invalidate();
}
/**
- * Set a simple drawable used for the left or right shadow.
- * The drawable provided must have a nonzero intrinsic width.
+ * Set a simple drawable used for the left or right shadow. The drawable provided must have a
+ * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
+ * instead of the drawable provided.
+ *
+ * <p>Note that for better support for both left-to-right and right-to-left layout
+ * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
+ * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
+ * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
+ * auto-mirrored such that the drawable will be mirrored in RTL layout.</p>
*
* @param resId Resource id of a shadow drawable to use at the edge of a drawer
* @param gravity Which drawer the shadow should apply to
@@ -417,7 +483,7 @@
*
* @param color Color to use in 0xAARRGGBB format.
*/
- public void setScrimColor(int color) {
+ public void setScrimColor(@ColorInt int color) {
mScrimColor = color;
invalidate();
}
@@ -867,6 +933,11 @@
heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
child.measure(contentWidthSpec, contentHeightSpec);
} else if (isDrawerView(child)) {
+ if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+ if (ViewCompat.getElevation(child) != mDrawerElevation) {
+ ViewCompat.setElevation(child, mDrawerElevation);
+ }
+ }
final int childGravity =
getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
if ((foundDrawers & childGravity) != 0) {
@@ -889,6 +960,65 @@
}
}
+ private void resolveShadowDrawables() {
+ if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+ return;
+ }
+ mShadowLeftResolved = resolveLeftShadow();
+ mShadowRightResolved = resolveRightShadow();
+ }
+
+ private Drawable resolveLeftShadow() {
+ int layoutDirection = ViewCompat.getLayoutDirection(this);
+ // Prefer shadows defined with start/end gravity over left and right.
+ if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
+ if (mShadowStart != null) {
+ // Correct drawable layout direction, if needed.
+ mirror(mShadowStart, layoutDirection);
+ return mShadowStart;
+ }
+ } else {
+ if (mShadowEnd != null) {
+ // Correct drawable layout direction, if needed.
+ mirror(mShadowEnd, layoutDirection);
+ return mShadowEnd;
+ }
+ }
+ return mShadowLeft;
+ }
+
+ private Drawable resolveRightShadow() {
+ int layoutDirection = ViewCompat.getLayoutDirection(this);
+ if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
+ if (mShadowEnd != null) {
+ // Correct drawable layout direction, if needed.
+ mirror(mShadowEnd, layoutDirection);
+ return mShadowEnd;
+ }
+ } else {
+ if (mShadowStart != null) {
+ // Correct drawable layout direction, if needed.
+ mirror(mShadowStart, layoutDirection);
+ return mShadowStart;
+ }
+ }
+ return mShadowRight;
+ }
+
+ /**
+ * Change the layout direction of the given drawable.
+ * Return true if auto-mirror is supported and drawable's layout direction can be changed.
+ * Otherwise, return false.
+ */
+ private boolean mirror(Drawable drawable, int layoutDirection) {
+ if (drawable == null || !DrawableCompat.isAutoMirrored(drawable)) {
+ return false;
+ }
+
+ DrawableCompat.setLayoutDirection(drawable, layoutDirection);
+ return true;
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mInLayout = true;
@@ -1042,11 +1172,15 @@
* @param color Color to use as a background drawable to draw behind the status bar
* in 0xAARRGGBB format.
*/
- public void setStatusBarBackgroundColor(int color) {
+ public void setStatusBarBackgroundColor(@ColorInt int color) {
mStatusBarBackground = new ColorDrawable(color);
invalidate();
}
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ resolveShadowDrawables();
+ }
+
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
@@ -1096,27 +1230,29 @@
mScrimPaint.setColor(color);
canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint);
- } else if (mShadowLeft != null && checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
- final int shadowWidth = mShadowLeft.getIntrinsicWidth();
+ } else if (mShadowLeftResolved != null
+ && checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
+ final int shadowWidth = mShadowLeftResolved.getIntrinsicWidth();
final int childRight = child.getRight();
final int drawerPeekDistance = mLeftDragger.getEdgeSize();
final float alpha =
Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f));
- mShadowLeft.setBounds(childRight, child.getTop(),
+ mShadowLeftResolved.setBounds(childRight, child.getTop(),
childRight + shadowWidth, child.getBottom());
- mShadowLeft.setAlpha((int) (0xff * alpha));
- mShadowLeft.draw(canvas);
- } else if (mShadowRight != null && checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) {
- final int shadowWidth = mShadowRight.getIntrinsicWidth();
+ mShadowLeftResolved.setAlpha((int) (0xff * alpha));
+ mShadowLeftResolved.draw(canvas);
+ } else if (mShadowRightResolved != null
+ && checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) {
+ final int shadowWidth = mShadowRightResolved.getIntrinsicWidth();
final int childLeft = child.getLeft();
final int showing = getWidth() - childLeft;
final int drawerPeekDistance = mRightDragger.getEdgeSize();
final float alpha =
Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f));
- mShadowRight.setBounds(childLeft - shadowWidth, child.getTop(),
+ mShadowRightResolved.setBounds(childLeft - shadowWidth, child.getTop(),
childLeft, child.getBottom());
- mShadowRight.setAlpha((int) (0xff * alpha));
- mShadowRight.draw(canvas);
+ mShadowRightResolved.setAlpha((int) (0xff * alpha));
+ mShadowRightResolved.draw(canvas);
}
return result;
}
diff --git a/v4/java/android/support/v4/widget/ExploreByTouchHelper.java b/v4/java/android/support/v4/widget/ExploreByTouchHelper.java
index 7adbc6f..64f6634 100644
--- a/v4/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/v4/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -45,11 +45,11 @@
* and managing accessibility focus. This class does not currently support
* hierarchies of logical items.
* <p>
- * This should be applied to the parent view using
- * {@link ViewCompat#setAccessibilityDelegate}:
+ * Clients should override abstract methods on this class and attach it to the
+ * host view using {@link ViewCompat#setAccessibilityDelegate}:
*
* <pre>
- * mAccessHelper = ExploreByTouchHelper.create(someView, mAccessHelperCallback);
+ * mAccessHelper = new MyExploreByTouchHelper(someView);
* ViewCompat.setAccessibilityDelegate(someView, mAccessHelper);
* </pre>
*/
@@ -57,6 +57,9 @@
/** Virtual node identifier value for invalid nodes. */
public static final int INVALID_ID = Integer.MIN_VALUE;
+ /** Virtual node identifier value for the host view's node. */
+ public static final int HOST_ID = View.NO_ID;
+
/** Default class name used for virtual views. */
private static final String DEFAULT_CLASS_NAME = View.class.getName();
@@ -191,7 +194,7 @@
* parent view.
*/
public void invalidateRoot() {
- invalidateVirtualView(View.NO_ID);
+ invalidateVirtualView(HOST_ID);
}
/**
@@ -243,7 +246,7 @@
/**
* Constructs and returns an {@link AccessibilityEvent} for the specified
- * virtual view id, which includes the host view ({@link View#NO_ID}).
+ * virtual view id, which includes the host view ({@link #HOST_ID}).
*
* @param virtualViewId The virtual view id for the item for which to
* construct an event.
@@ -253,7 +256,7 @@
*/
private AccessibilityEvent createEvent(int virtualViewId, int eventType) {
switch (virtualViewId) {
- case View.NO_ID:
+ case HOST_ID:
return createEventForHost(eventType);
default:
return createEventForChild(virtualViewId, eventType);
@@ -309,7 +312,7 @@
/**
* Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
* specified virtual view id, which includes the host view
- * ({@link View#NO_ID}).
+ * ({@link #HOST_ID}).
*
* @param virtualViewId The virtual view id for the item for which to
* construct a node.
@@ -318,7 +321,7 @@
*/
private AccessibilityNodeInfoCompat createNode(int virtualViewId) {
switch (virtualViewId) {
- case View.NO_ID:
+ case HOST_ID:
return createNodeForHost();
default:
return createNodeForChild(virtualViewId);
@@ -335,6 +338,9 @@
final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain(mView);
ViewCompat.onInitializeAccessibilityNodeInfo(mView, node);
+ // Allow the client to populate the host node.
+ onPopulateNodeForHost(node);
+
// Add the virtual descendants.
final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>();
getVisibleVirtualViews(virtualViewIds);
@@ -439,7 +445,7 @@
private boolean performAction(int virtualViewId, int action, Bundle arguments) {
switch (virtualViewId) {
- case View.NO_ID:
+ case HOST_ID:
return performActionForHost(action, arguments);
default:
return performActionForChild(virtualViewId, action, arguments);
@@ -542,7 +548,15 @@
}
// TODO: Check virtual view visibility.
if (!isAccessibilityFocused(virtualViewId)) {
+ // Clear focus from the previously focused view, if applicable.
+ if (mFocusedVirtualViewId != INVALID_ID) {
+ sendEventForVirtualView(mFocusedVirtualViewId,
+ AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+ }
+
+ // Set focus on the new view.
mFocusedVirtualViewId = virtualViewId;
+
// TODO: Only invalidate virtual view bounds.
mView.invalidate();
sendEventForVirtualView(virtualViewId,
@@ -577,7 +591,7 @@
* @param x The view-relative x coordinate
* @param y The view-relative y coordinate
* @return virtual view identifier for the logical item under
- * coordinates (x,y) or {@link View#NO_ID} if there is no item at
+ * coordinates (x,y) or {@link #HOST_ID} if there is no item at
* the given coordinates
*/
protected abstract int getVirtualViewAt(float x, float y);
@@ -683,6 +697,17 @@
int virtualViewId, AccessibilityNodeInfoCompat node);
/**
+ * Populates an {@link AccessibilityNodeInfoCompat} with information
+ * about the host view.
+ * <p>
+ * The following required fields are automatically populated by the
+ * helper class and may not be overridden:
+ */
+ public void onPopulateNodeForHost(AccessibilityNodeInfoCompat node) {
+ // Default implementation is no-op.
+ }
+
+ /**
* Performs the specified accessibility action on the item associated
* with the virtual view identifier. See
* {@link AccessibilityNodeInfoCompat#performAction(int, Bundle)} for
diff --git a/v4/java/android/support/v4/widget/PopupWindowCompat.java b/v4/java/android/support/v4/widget/PopupWindowCompat.java
index be96a73..7f4c828 100644
--- a/v4/java/android/support/v4/widget/PopupWindowCompat.java
+++ b/v4/java/android/support/v4/widget/PopupWindowCompat.java
@@ -17,7 +17,7 @@
package android.support.v4.widget;
import android.view.View;
-import android.view.View.OnTouchListener;
+import android.view.WindowManager;
import android.widget.PopupWindow;
/**
@@ -29,8 +29,11 @@
* Interface for the full API.
*/
interface PopupWindowImpl {
- public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
- int gravity);
+ void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff, int gravity);
+ void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor);
+ boolean getOverlapAnchor(PopupWindow popupWindow);
+ void setWindowLayoutType(PopupWindow popupWindow, int layoutType);
+ int getWindowLayoutType(PopupWindow popupWindow);
}
/**
@@ -42,12 +45,47 @@
int gravity) {
popup.showAsDropDown(anchor, xoff, yoff);
}
+
+ @Override
+ public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ // noop
+ }
+
+ @Override
+ public boolean getOverlapAnchor(PopupWindow popupWindow) {
+ return false;
+ }
+
+ @Override
+ public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ // no-op
+ }
+
+ @Override
+ public int getWindowLayoutType(PopupWindow popupWindow) {
+ return 0;
+ }
+ }
+
+ /**
+ * Interface implementation that doesn't use anything above v4 APIs.
+ */
+ static class GingerbreadPopupWindowImpl extends BasePopupWindowImpl {
+ @Override
+ public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ PopupWindowCompatGingerbread.setWindowLayoutType(popupWindow, layoutType);
+ }
+
+ @Override
+ public int getWindowLayoutType(PopupWindow popupWindow) {
+ return PopupWindowCompatGingerbread.getWindowLayoutType(popupWindow);
+ }
}
/**
* Interface implementation for devices with at least KitKat APIs.
*/
- static class KitKatPopupWindowImpl extends BasePopupWindowImpl {
+ static class KitKatPopupWindowImpl extends GingerbreadPopupWindowImpl {
@Override
public void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
int gravity) {
@@ -55,14 +93,54 @@
}
}
+ static class Api21PopupWindowImpl extends KitKatPopupWindowImpl {
+ @Override
+ public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ PopupWindowCompatApi21.setOverlapAnchor(popupWindow, overlapAnchor);
+ }
+
+ @Override
+ public boolean getOverlapAnchor(PopupWindow popupWindow) {
+ return PopupWindowCompatApi21.getOverlapAnchor(popupWindow);
+ }
+ }
+
+ static class Api23PopupWindowImpl extends Api21PopupWindowImpl {
+ @Override
+ public void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ PopupWindowCompatApi23.setOverlapAnchor(popupWindow, overlapAnchor);
+ }
+
+ @Override
+ public boolean getOverlapAnchor(PopupWindow popupWindow) {
+ return PopupWindowCompatApi23.getOverlapAnchor(popupWindow);
+ }
+
+ @Override
+ public void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ PopupWindowCompatApi23.setWindowLayoutType(popupWindow, layoutType);
+ }
+
+ @Override
+ public int getWindowLayoutType(PopupWindow popupWindow) {
+ return PopupWindowCompatApi23.getWindowLayoutType(popupWindow);
+ }
+ }
+
/**
* Select the correct implementation to use for the current platform.
*/
static final PopupWindowImpl IMPL;
static {
final int version = android.os.Build.VERSION.SDK_INT;
- if (version >= 19) {
+ if (version >= 23) {
+ IMPL = new Api23PopupWindowImpl();
+ } else if (version >= 21) {
+ IMPL = new Api21PopupWindowImpl();
+ } else if (version >= 19) {
IMPL = new KitKatPopupWindowImpl();
+ } else if (version >= 9) {
+ IMPL = new GingerbreadPopupWindowImpl();
} else {
IMPL = new BasePopupWindowImpl();
}
@@ -92,4 +170,46 @@
int gravity) {
IMPL.showAsDropDown(popup, anchor, xoff, yoff, gravity);
}
+
+ /**
+ * Sets whether the popup window should overlap its anchor view when
+ * displayed as a drop-down.
+ *
+ * @param overlapAnchor Whether the popup should overlap its anchor.
+ */
+ public static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ IMPL.setOverlapAnchor(popupWindow, overlapAnchor);
+ }
+
+ /**
+ * Returns whether the popup window should overlap its anchor view when
+ * displayed as a drop-down.
+ *
+ * @return Whether the popup should overlap its anchor.
+ */
+ public static boolean getOverlapAnchor(PopupWindow popupWindow) {
+ return IMPL.getOverlapAnchor(popupWindow);
+ }
+
+ /**
+ * Set the layout type for this window. This value will be passed through to
+ * {@link WindowManager.LayoutParams#type} therefore the value should match any value
+ * {@link WindowManager.LayoutParams#type} accepts.
+ *
+ * @param layoutType Layout type for this window.
+ *
+ * @see WindowManager.LayoutParams#type
+ */
+ public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ IMPL.setWindowLayoutType(popupWindow, layoutType);
+ }
+
+ /**
+ * Returns the layout type for this window.
+ *
+ * @see #setWindowLayoutType(PopupWindow popupWindow, int)
+ */
+ public static int getWindowLayoutType(PopupWindow popupWindow) {
+ return IMPL.getWindowLayoutType(popupWindow);
+ }
}
diff --git a/v4/java/android/support/v4/widget/SlidingPaneLayout.java b/v4/java/android/support/v4/widget/SlidingPaneLayout.java
index 391ba99..c5db3ef 100644
--- a/v4/java/android/support/v4/widget/SlidingPaneLayout.java
+++ b/v4/java/android/support/v4/widget/SlidingPaneLayout.java
@@ -29,6 +29,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.MotionEventCompat;
@@ -297,13 +298,14 @@
*
* @param color An ARGB-packed color value
*/
- public void setSliderFadeColor(int color) {
+ public void setSliderFadeColor(@ColorInt int color) {
mSliderFadeColor = color;
}
/**
* @return The ARGB-packed color value used to fade the sliding pane
*/
+ @ColorInt
public int getSliderFadeColor() {
return mSliderFadeColor;
}
@@ -314,13 +316,14 @@
*
* @param color An ARGB-packed color value
*/
- public void setCoveredFadeColor(int color) {
+ public void setCoveredFadeColor(@ColorInt int color) {
mCoveredFadeColor = color;
}
/**
* @return The ARGB-packed color value used to fade the fixed pane
*/
+ @ColorInt
public int getCoveredFadeColor() {
return mCoveredFadeColor;
}
diff --git a/v4/java/android/support/v4/widget/SwipeRefreshLayout.java b/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
index 7e20d88..d6b35ef 100644
--- a/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
+++ b/v4/java/android/support/v4/widget/SwipeRefreshLayout.java
@@ -19,6 +19,8 @@
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
@@ -476,7 +478,7 @@
*
* @param colorRes Resource id of the color.
*/
- public void setProgressBackgroundColorSchemeResource(int colorRes) {
+ public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {
setProgressBackgroundColorSchemeColor(getResources().getColor(colorRes));
}
@@ -485,7 +487,7 @@
*
* @param color
*/
- public void setProgressBackgroundColorSchemeColor(int color) {
+ public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {
mCircleView.setBackgroundColor(color);
mProgress.setBackgroundColor(color);
}
@@ -494,7 +496,7 @@
* @deprecated Use {@link #setColorSchemeResources(int...)}
*/
@Deprecated
- public void setColorScheme(int... colors) {
+ public void setColorScheme(@ColorInt int... colors) {
setColorSchemeResources(colors);
}
@@ -505,7 +507,7 @@
*
* @param colorResIds
*/
- public void setColorSchemeResources(int... colorResIds) {
+ public void setColorSchemeResources(@ColorRes int... colorResIds) {
final Resources res = getResources();
int[] colorRes = new int[colorResIds.length];
for (int i = 0; i < colorResIds.length; i++) {
@@ -521,6 +523,7 @@
*
* @param colors
*/
+ @ColorInt
public void setColorSchemeColors(int... colors) {
ensureTarget();
mProgress.setColorSchemeColors(colors);
diff --git a/v4/jellybean-mr1/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr1.java b/v4/jellybean-mr1/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr1.java
new file mode 100644
index 0000000..a4b9677
--- /dev/null
+++ b/v4/jellybean-mr1/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr1.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view.accessibility;
+
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+class AccessibilityNodeInfoCompatJellybeanMr1 {
+
+ public static void setLabelFor(Object info, View labeled) {
+ ((AccessibilityNodeInfo) info).setLabelFor(labeled);
+ }
+
+ public static void setLabelFor(Object info, View root, int virtualDescendantId) {
+ ((AccessibilityNodeInfo) info).setLabelFor(root, virtualDescendantId);
+ }
+
+ public static Object getLabelFor(Object info) {
+ return ((AccessibilityNodeInfo) info).getLabelFor();
+ }
+
+ public static void setLabeledBy(Object info, View labeled) {
+ ((AccessibilityNodeInfo) info).setLabeledBy(labeled);
+ }
+
+ public static void setLabeledBy(Object info, View root, int virtualDescendantId) {
+ ((AccessibilityNodeInfo) info).setLabeledBy(root, virtualDescendantId);
+ }
+
+ public static Object getLabeledBy(Object info) {
+ return ((AccessibilityNodeInfo) info).getLabeledBy();
+ }
+}
diff --git a/v4/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java b/v4/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java
index 2b76ea0..e48d9f7 100644
--- a/v4/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java
+++ b/v4/jellybean-mr2/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatJellybeanMr2.java
@@ -18,6 +18,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
+import java.util.List;
+
class AccessibilityNodeInfoCompatJellybeanMr2 {
public static void setViewIdResourceName(Object info, String viewId) {
@@ -27,4 +29,34 @@
public static String getViewIdResourceName(Object info) {
return ((AccessibilityNodeInfo) info).getViewIdResourceName();
}
+
+ @SuppressWarnings("unchecked")
+ public static List<Object> findAccessibilityNodeInfosByViewId(Object info, String viewId) {
+ Object result = ((AccessibilityNodeInfo) info).findAccessibilityNodeInfosByViewId(viewId);
+ return (List<Object>) result;
+ }
+
+ public static void setTextSelection(Object info, int start, int end) {
+ ((AccessibilityNodeInfo) info).setTextSelection(start, end);
+ }
+
+ public static int getTextSelectionStart(Object info) {
+ return ((AccessibilityNodeInfo) info).getTextSelectionStart();
+ }
+
+ public static int getTextSelectionEnd(Object info) {
+ return ((AccessibilityNodeInfo) info).getTextSelectionEnd();
+ }
+
+ public static boolean isEditable(Object info) {
+ return ((AccessibilityNodeInfo) info).isEditable();
+ }
+
+ public static void setEditable(Object info, boolean editable) {
+ ((AccessibilityNodeInfo) info).setEditable(editable);
+ }
+
+ public static boolean refresh(Object info) {
+ return ((AccessibilityNodeInfo) info).refresh();
+ }
}
diff --git a/v4/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java b/v4/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java
new file mode 100644
index 0000000..ef05746
--- /dev/null
+++ b/v4/jellybean/android/support/v4/content/ContentResolverCompatJellybean.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+
+class ContentResolverCompatJellybean {
+ public static Cursor query(ContentResolver resolver, Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ Object cancellationSignalObj) {
+ return resolver.query(uri, projection, selection, selectionArgs, sortOrder,
+ (android.os.CancellationSignal)cancellationSignalObj);
+ }
+}
diff --git a/v4/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java b/v4/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java
new file mode 100644
index 0000000..6029286
--- /dev/null
+++ b/v4/jellybean/android/support/v4/os/CancellationSignalCompatJellybean.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.os;
+
+class CancellationSignalCompatJellybean {
+ public static Object create() {
+ return new android.os.CancellationSignal();
+ }
+
+ public static void cancel(Object cancellationSignalObj) {
+ ((android.os.CancellationSignal)cancellationSignalObj).cancel();
+ }
+}
diff --git a/v4/jellybean/android/support/v4/view/ViewCompatJB.java b/v4/jellybean/android/support/v4/view/ViewCompatJB.java
index 9373572..f1c7315 100644
--- a/v4/jellybean/android/support/v4/view/ViewCompatJB.java
+++ b/v4/jellybean/android/support/v4/view/ViewCompatJB.java
@@ -85,4 +85,8 @@
public static boolean getFitsSystemWindows(View view) {
return view.getFitsSystemWindows();
}
+
+ public static boolean hasOverlappingRendering(View view) {
+ return view.hasOverlappingRendering();
+ }
}
diff --git a/v4/kitkat/android/support/v4/print/PrintHelperKitkat.java b/v4/kitkat/android/support/v4/print/PrintHelperKitkat.java
index b827b1f..091d5a4 100644
--- a/v4/kitkat/android/support/v4/print/PrintHelperKitkat.java
+++ b/v4/kitkat/android/support/v4/print/PrintHelperKitkat.java
@@ -18,8 +18,13 @@
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.pdf.PdfDocument.Page;
import android.net.Uri;
@@ -208,16 +213,20 @@
WriteResultCallback writeResultCallback) {
PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
mAttributes);
+
+ Bitmap maybeGrayscale = convertBitmapForColorMode(bitmap,
+ mAttributes.getColorMode());
try {
Page page = pdfDocument.startPage(1);
RectF content = new RectF(page.getInfo().getContentRect());
- Matrix matrix = getMatrix(bitmap.getWidth(), bitmap.getHeight(),
+ Matrix matrix = getMatrix(
+ maybeGrayscale.getWidth(), maybeGrayscale.getHeight(),
content, fittingMode);
// Draw the bitmap.
- page.getCanvas().drawBitmap(bitmap, matrix, null);
+ page.getCanvas().drawBitmap(maybeGrayscale, matrix, null);
// Finish the page.
pdfDocument.finishPage(page);
@@ -245,6 +254,10 @@
/* ignore */
}
}
+ // If we created a new instance for grayscaling, then recycle it here.
+ if (maybeGrayscale != bitmap) {
+ maybeGrayscale.recycle();
+ }
}
}
@@ -401,6 +414,10 @@
if (callback != null) {
callback.onFinish();
}
+ if (mBitmap != null) {
+ mBitmap.recycle();
+ mBitmap = null;
+ }
}
@Override
@@ -409,6 +426,8 @@
WriteResultCallback writeResultCallback) {
PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
mAttributes);
+ Bitmap maybeGrayscale = convertBitmapForColorMode(mBitmap,
+ mAttributes.getColorMode());
try {
Page page = pdfDocument.startPage(1);
@@ -419,7 +438,7 @@
content, fittingMode);
// Draw the bitmap.
- page.getCanvas().drawBitmap(mBitmap, matrix, null);
+ page.getCanvas().drawBitmap(maybeGrayscale, matrix, null);
// Finish the page.
pdfDocument.finishPage(page);
@@ -447,6 +466,10 @@
/* ignore */
}
}
+ // If we created a new instance for grayscaling, then recycle it here.
+ if (maybeGrayscale != mBitmap) {
+ maybeGrayscale.recycle();
+ }
}
}
};
@@ -541,4 +564,23 @@
}
}
}
+
+ private Bitmap convertBitmapForColorMode(Bitmap original, int colorMode) {
+ if (colorMode != COLOR_MODE_MONOCHROME) {
+ return original;
+ }
+ // Create a grayscale bitmap
+ Bitmap grayscale = Bitmap.createBitmap(original.getWidth(), original.getHeight(),
+ Config.ARGB_8888);
+ Canvas c = new Canvas(grayscale);
+ Paint p = new Paint();
+ ColorMatrix cm = new ColorMatrix();
+ cm.setSaturation(0);
+ ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
+ p.setColorFilter(f);
+ c.drawBitmap(original, 0, 0, p);
+ c.setBitmap(null);
+
+ return grayscale;
+ }
}
\ No newline at end of file
diff --git a/v4/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java b/v4/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java
index 32fb86f..3805d02 100644
--- a/v4/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java
+++ b/v4/kitkat/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatKitKat.java
@@ -16,6 +16,7 @@
package android.support.v4.view.accessibility;
+import android.os.Bundle;
import android.view.accessibility.AccessibilityNodeInfo;
/**
@@ -52,6 +53,10 @@
return ((AccessibilityNodeInfo) info).getRangeInfo();
}
+ public static void setRangeInfo(Object info, Object rangeInfo) {
+ ((AccessibilityNodeInfo) info).setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo);
+ }
+
public static Object obtainCollectionInfo(int rowCount, int columnCount,
boolean hierarchical, int selectionMode) {
return AccessibilityNodeInfo.CollectionInfo.obtain(rowCount, columnCount, hierarchical);
@@ -71,6 +76,42 @@
return ((AccessibilityNodeInfo) info).isContentInvalid();
}
+ public static boolean canOpenPopup(Object info) {
+ return ((AccessibilityNodeInfo) info).canOpenPopup();
+ }
+
+ public static void setCanOpenPopup(Object info, boolean opensPopup) {
+ ((AccessibilityNodeInfo) info).setCanOpenPopup(opensPopup);
+ }
+
+ public static Bundle getExtras(Object info) {
+ return ((AccessibilityNodeInfo) info).getExtras();
+ }
+
+ public static int getInputType(Object info) {
+ return ((AccessibilityNodeInfo) info).getInputType();
+ }
+
+ public static void setInputType(Object info, int inputType) {
+ ((AccessibilityNodeInfo) info).setInputType(inputType);
+ }
+
+ public static boolean isDismissable(Object info) {
+ return ((AccessibilityNodeInfo) info).isDismissable();
+ }
+
+ public static void setDismissable(Object info, boolean dismissable) {
+ ((AccessibilityNodeInfo) info).setDismissable(dismissable);
+ }
+
+ public static boolean isMultiLine(Object info) {
+ return ((AccessibilityNodeInfo) info).isMultiLine();
+ }
+
+ public static void setMultiLine(Object info, boolean multiLine) {
+ ((AccessibilityNodeInfo) info).setMultiLine(multiLine);
+ }
+
static class CollectionInfo {
static int getColumnCount(Object info) {
return ((AccessibilityNodeInfo.CollectionInfo) info).getColumnCount();
diff --git a/v7/appcompat/api/current.txt b/v7/appcompat/api/current.txt
index 7651979..b26b4e8 100644
--- a/v7/appcompat/api/current.txt
+++ b/v7/appcompat/api/current.txt
@@ -244,6 +244,7 @@
public abstract class AppCompatDelegate {
method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public abstract void applyDayNight();
method public static android.support.v7.app.AppCompatDelegate create(android.app.Activity, android.support.v7.app.AppCompatCallback);
method public static android.support.v7.app.AppCompatDelegate create(android.app.Dialog, android.support.v7.app.AppCompatCallback);
method public abstract android.view.View createView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
@@ -265,9 +266,16 @@
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public abstract void setHandleNativeActionModesEnabled(boolean);
+ method public abstract void setNightMode(int);
method public abstract void setSupportActionBar(android.support.v7.widget.Toolbar);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract android.support.v7.view.ActionMode startSupportActionMode(android.support.v7.view.ActionMode.Callback);
+ field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+ field public static final int FEATURE_SUPPORT_ACTION_BAR = 108; // 0x6c
+ field public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY = 109; // 0x6d
+ field public static final int MODE_NIGHT_AUTO = 2; // 0x2
+ field public static final int MODE_NIGHT_NO = 0; // 0x0
+ field public static final int MODE_NIGHT_YES = 1; // 0x1
}
public class AppCompatDialog extends android.app.Dialog implements android.support.v7.app.AppCompatCallback {
@@ -282,6 +290,10 @@
method public boolean supportRequestWindowFeature(int);
}
+ public class AppCompatDialogFragment extends android.support.v4.app.DialogFragment {
+ ctor public AppCompatDialogFragment();
+ }
+
public class NotificationCompat extends android.support.v4.app.NotificationCompat {
ctor public NotificationCompat();
}
@@ -377,6 +389,8 @@
field public static int buttonPanelSideLayout;
field public static int buttonStyle;
field public static int buttonStyleSmall;
+ field public static int buttonTint;
+ field public static int buttonTintMode;
field public static int checkboxStyle;
field public static int checkedTextViewStyle;
field public static int closeIcon;
@@ -397,11 +411,11 @@
field public static int contentInsetLeft;
field public static int contentInsetRight;
field public static int contentInsetStart;
+ field public static int controlBackground;
field public static int customNavigationLayout;
field public static int defaultQueryHint;
field public static int dialogPreferredPadding;
field public static int dialogTheme;
- field public static int disableChildrenWhenDisabled;
field public static int displayOptions;
field public static int divider;
field public static int dividerHorizontal;
@@ -440,6 +454,7 @@
field public static int listPreferredItemPaddingLeft;
field public static int listPreferredItemPaddingRight;
field public static int logo;
+ field public static int logoDescription;
field public static int maxButtonHeight;
field public static int measureWithLargestChild;
field public static int middleBarArrowSize;
@@ -454,13 +469,11 @@
field public static int panelMenuListTheme;
field public static int panelMenuListWidth;
field public static int popupMenuStyle;
- field public static int popupPromptView;
field public static int popupTheme;
field public static int popupWindowStyle;
field public static int preserveIconSpacing;
field public static int progressBarPadding;
field public static int progressBarStyle;
- field public static int prompt;
field public static int queryBackground;
field public static int queryHint;
field public static int radioButtonStyle;
@@ -476,13 +489,13 @@
field public static int singleChoiceItemLayout;
field public static int spinBars;
field public static int spinnerDropDownItemStyle;
- field public static int spinnerMode;
field public static int spinnerStyle;
field public static int splitTrack;
field public static int state_above_anchor;
field public static int submitBackground;
field public static int subtitle;
field public static int subtitleTextAppearance;
+ field public static int subtitleTextColor;
field public static int subtitleTextStyle;
field public static int suggestionRowLayout;
field public static int switchMinWidth;
@@ -508,6 +521,7 @@
field public static int titleMarginTop;
field public static int titleMargins;
field public static int titleTextAppearance;
+ field public static int titleTextColor;
field public static int titleTextStyle;
field public static int toolbarNavigationButtonStyle;
field public static int toolbarStyle;
@@ -541,6 +555,7 @@
ctor public R.color();
field public static int abc_background_cache_hint_selector_material_dark;
field public static int abc_background_cache_hint_selector_material_light;
+ field public static int abc_color_highlight_material;
field public static int abc_input_method_navigation_guard;
field public static int abc_primary_text_disable_only_material_dark;
field public static int abc_primary_text_disable_only_material_light;
@@ -570,6 +585,8 @@
field public static int dim_foreground_disabled_material_light;
field public static int dim_foreground_material_dark;
field public static int dim_foreground_material_light;
+ field public static int foreground_material_dark;
+ field public static int foreground_material_light;
field public static int highlighted_text_material_dark;
field public static int highlighted_text_material_light;
field public static int hint_foreground_material_dark;
@@ -581,6 +598,13 @@
field public static int material_blue_grey_950;
field public static int material_deep_teal_200;
field public static int material_deep_teal_500;
+ field public static int material_grey_100;
+ field public static int material_grey_300;
+ field public static int material_grey_50;
+ field public static int material_grey_600;
+ field public static int material_grey_800;
+ field public static int material_grey_850;
+ field public static int material_grey_900;
field public static int primary_dark_material_dark;
field public static int primary_dark_material_light;
field public static int primary_material_dark;
@@ -671,6 +695,9 @@
field public static int dialog_fixed_width_minor;
field public static int disabled_alpha_material_dark;
field public static int disabled_alpha_material_light;
+ field public static int highlight_alpha_material_colored;
+ field public static int highlight_alpha_material_dark;
+ field public static int highlight_alpha_material_light;
field public static int notification_large_icon_height;
field public static int notification_large_icon_width;
field public static int notification_subtext_size;
@@ -679,10 +706,12 @@
public static final class R.drawable {
ctor public R.drawable();
field public static int abc_ab_share_pack_mtrl_alpha;
+ field public static int abc_action_bar_item_background_material;
field public static int abc_btn_borderless_material;
field public static int abc_btn_check_material;
field public static int abc_btn_check_to_on_mtrl_000;
field public static int abc_btn_check_to_on_mtrl_015;
+ field public static int abc_btn_colored_material;
field public static int abc_btn_default_mtrl_shape;
field public static int abc_btn_radio_material;
field public static int abc_btn_radio_to_on_mtrl_000;
@@ -694,6 +723,7 @@
field public static int abc_cab_background_internal_bg;
field public static int abc_cab_background_top_material;
field public static int abc_cab_background_top_mtrl_alpha;
+ field public static int abc_control_background_material;
field public static int abc_dialog_material_background_dark;
field public static int abc_dialog_material_background_light;
field public static int abc_edit_text_material;
@@ -731,7 +761,7 @@
field public static int abc_switch_track_mtrl_alpha;
field public static int abc_tab_indicator_material;
field public static int abc_tab_indicator_mtrl_alpha;
- field public static int abc_text_cursor_mtrl_alpha;
+ field public static int abc_text_cursor_material;
field public static int abc_textfield_activated_mtrl_alpha;
field public static int abc_textfield_default_mtrl_alpha;
field public static int abc_textfield_search_activated_mtrl_alpha;
@@ -771,9 +801,7 @@
field public static int customPanel;
field public static int decor_content_parent;
field public static int default_activity_button;
- field public static int dialog;
field public static int disableHome;
- field public static int dropdown;
field public static int edit_query;
field public static int end;
field public static int end_padder;
@@ -871,7 +899,6 @@
field public static int abc_search_dropdown_item_icons_2line;
field public static int abc_search_view;
field public static int abc_select_dialog_material;
- field public static int abc_simple_dropdown_hint;
field public static int notification_media_action;
field public static int notification_media_cancel_action;
field public static int notification_template_big_media;
@@ -954,6 +981,8 @@
field public static int Base_TextAppearance_AppCompat_Widget_ActionBar_Title_Inverse;
field public static int Base_TextAppearance_AppCompat_Widget_ActionMode_Subtitle;
field public static int Base_TextAppearance_AppCompat_Widget_ActionMode_Title;
+ field public static int Base_TextAppearance_AppCompat_Widget_Button;
+ field public static int Base_TextAppearance_AppCompat_Widget_Button_Inverse;
field public static int Base_TextAppearance_AppCompat_Widget_DropDownItem;
field public static int Base_TextAppearance_AppCompat_Widget_PopupMenu_Large;
field public static int Base_TextAppearance_AppCompat_Widget_PopupMenu_Small;
@@ -991,6 +1020,8 @@
field public static int Base_V21_Theme_AppCompat_Light_Dialog;
field public static int Base_V22_Theme_AppCompat;
field public static int Base_V22_Theme_AppCompat_Light;
+ field public static int Base_V23_Theme_AppCompat;
+ field public static int Base_V23_Theme_AppCompat_Light;
field public static int Base_V7_Theme_AppCompat;
field public static int Base_V7_Theme_AppCompat_Dialog;
field public static int Base_V7_Theme_AppCompat_Light;
@@ -1014,6 +1045,7 @@
field public static int Base_Widget_AppCompat_Button_Borderless;
field public static int Base_Widget_AppCompat_Button_Borderless_Colored;
field public static int Base_Widget_AppCompat_Button_ButtonBar_AlertDialog;
+ field public static int Base_Widget_AppCompat_Button_Colored;
field public static int Base_Widget_AppCompat_Button_Small;
field public static int Base_Widget_AppCompat_CompoundButton_CheckBox;
field public static int Base_Widget_AppCompat_CompoundButton_RadioButton;
@@ -1043,7 +1075,6 @@
field public static int Base_Widget_AppCompat_SearchView;
field public static int Base_Widget_AppCompat_SearchView_ActionBar;
field public static int Base_Widget_AppCompat_Spinner;
- field public static int Base_Widget_AppCompat_Spinner_DropDown_ActionBar;
field public static int Base_Widget_AppCompat_Spinner_Underlined;
field public static int Base_Widget_AppCompat_TextView_SpinnerItem;
field public static int Base_Widget_AppCompat_Toolbar;
@@ -1057,6 +1088,7 @@
field public static int Platform_V11_AppCompat_Light;
field public static int Platform_V14_AppCompat;
field public static int Platform_V14_AppCompat_Light;
+ field public static int Platform_Widget_AppCompat_Spinner;
field public static int RtlOverlay_DialogWindowTitle_AppCompat;
field public static int RtlOverlay_Widget_AppCompat_ActionBar_TitleItem;
field public static int RtlOverlay_Widget_AppCompat_ActionButton_Overflow;
@@ -1108,6 +1140,8 @@
field public static int TextAppearance_AppCompat_Widget_ActionMode_Subtitle_Inverse;
field public static int TextAppearance_AppCompat_Widget_ActionMode_Title;
field public static int TextAppearance_AppCompat_Widget_ActionMode_Title_Inverse;
+ field public static int TextAppearance_AppCompat_Widget_Button;
+ field public static int TextAppearance_AppCompat_Widget_Button_Inverse;
field public static int TextAppearance_AppCompat_Widget_DropDownItem;
field public static int TextAppearance_AppCompat_Widget_PopupMenu_Large;
field public static int TextAppearance_AppCompat_Widget_PopupMenu_Small;
@@ -1128,6 +1162,13 @@
field public static int ThemeOverlay_AppCompat_Light;
field public static int Theme_AppCompat;
field public static int Theme_AppCompat_CompactMenu;
+ field public static int Theme_AppCompat_DayNight;
+ field public static int Theme_AppCompat_DayNight_DarkActionBar;
+ field public static int Theme_AppCompat_DayNight_Dialog;
+ field public static int Theme_AppCompat_DayNight_DialogWhenLarge;
+ field public static int Theme_AppCompat_DayNight_Dialog_Alert;
+ field public static int Theme_AppCompat_DayNight_Dialog_MinWidth;
+ field public static int Theme_AppCompat_DayNight_NoActionBar;
field public static int Theme_AppCompat_Dialog;
field public static int Theme_AppCompat_DialogWhenLarge;
field public static int Theme_AppCompat_Dialog_Alert;
@@ -1157,6 +1198,7 @@
field public static int Widget_AppCompat_Button_Borderless;
field public static int Widget_AppCompat_Button_Borderless_Colored;
field public static int Widget_AppCompat_Button_ButtonBar_AlertDialog;
+ field public static int Widget_AppCompat_Button_Colored;
field public static int Widget_AppCompat_Button_Small;
field public static int Widget_AppCompat_CompoundButton_CheckBox;
field public static int Widget_AppCompat_CompoundButton_RadioButton;
@@ -1262,6 +1304,10 @@
field public static final int[] AppCompatTextView;
field public static int AppCompatTextView_android_textAppearance;
field public static int AppCompatTextView_textAllCaps;
+ field public static final int[] CompoundButton;
+ field public static int CompoundButton_android_button;
+ field public static int CompoundButton_buttonTint;
+ field public static int CompoundButton_buttonTintMode;
field public static final int[] DrawerArrowToggle;
field public static int DrawerArrowToggle_barSize;
field public static int DrawerArrowToggle_color;
@@ -1347,17 +1393,10 @@
field public static int SearchView_suggestionRowLayout;
field public static int SearchView_voiceIcon;
field public static final int[] Spinner;
- field public static int Spinner_android_background;
- field public static int Spinner_android_dropDownHorizontalOffset;
- field public static int Spinner_android_dropDownSelector;
- field public static int Spinner_android_dropDownVerticalOffset;
field public static int Spinner_android_dropDownWidth;
- field public static int Spinner_android_gravity;
field public static int Spinner_android_popupBackground;
- field public static int Spinner_disableChildrenWhenDisabled;
- field public static int Spinner_popupPromptView;
- field public static int Spinner_prompt;
- field public static int Spinner_spinnerMode;
+ field public static int Spinner_android_prompt;
+ field public static int Spinner_popupTheme;
field public static final int[] SwitchCompat;
field public static int SwitchCompat_android_textOff;
field public static int SwitchCompat_android_textOn;
@@ -1432,6 +1471,7 @@
field public static int Theme_colorPrimary;
field public static int Theme_colorPrimaryDark;
field public static int Theme_colorSwitchThumbNormal;
+ field public static int Theme_controlBackground;
field public static int Theme_dialogPreferredPadding;
field public static int Theme_dialogTheme;
field public static int Theme_dividerHorizontal;
@@ -1492,12 +1532,15 @@
field public static int Toolbar_contentInsetLeft;
field public static int Toolbar_contentInsetRight;
field public static int Toolbar_contentInsetStart;
+ field public static int Toolbar_logo;
+ field public static int Toolbar_logoDescription;
field public static int Toolbar_maxButtonHeight;
field public static int Toolbar_navigationContentDescription;
field public static int Toolbar_navigationIcon;
field public static int Toolbar_popupTheme;
field public static int Toolbar_subtitle;
field public static int Toolbar_subtitleTextAppearance;
+ field public static int Toolbar_subtitleTextColor;
field public static int Toolbar_title;
field public static int Toolbar_titleMarginBottom;
field public static int Toolbar_titleMarginEnd;
@@ -1505,15 +1548,18 @@
field public static int Toolbar_titleMarginTop;
field public static int Toolbar_titleMargins;
field public static int Toolbar_titleTextAppearance;
+ field public static int Toolbar_titleTextColor;
field public static final int[] View;
+ field public static final int[] ViewBackgroundHelper;
+ field public static int ViewBackgroundHelper_android_background;
+ field public static int ViewBackgroundHelper_backgroundTint;
+ field public static int ViewBackgroundHelper_backgroundTintMode;
field public static final int[] ViewStubCompat;
field public static int ViewStubCompat_android_id;
field public static int ViewStubCompat_android_inflatedId;
field public static int ViewStubCompat_android_layout;
field public static int View_android_focusable;
field public static int View_android_theme;
- field public static int View_backgroundTint;
- field public static int View_backgroundTintMode;
field public static int View_paddingEnd;
field public static int View_paddingStart;
field public static int View_theme;
@@ -1584,12 +1630,14 @@
ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
method public void dismissPopupMenus();
method public android.view.Menu getMenu();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public boolean hideOverflowMenu();
method public boolean isOverflowMenuShowing();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onDetachedFromWindow();
method public void setOnMenuItemClickListener(android.support.v7.widget.ActionMenuView.OnMenuItemClickListener);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public boolean showOverflowMenu();
}
@@ -1620,6 +1668,7 @@
ctor public AppCompatButton(android.content.Context);
ctor public AppCompatButton(android.content.Context, android.util.AttributeSet);
ctor public AppCompatButton(android.content.Context, android.util.AttributeSet, int);
+ method public void setSupportAllCaps(boolean);
}
public class AppCompatCheckBox extends android.widget.CheckBox {
@@ -1660,8 +1709,11 @@
public class AppCompatSpinner extends android.widget.Spinner {
ctor public AppCompatSpinner(android.content.Context);
+ ctor public AppCompatSpinner(android.content.Context, int);
ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet);
ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int);
+ ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public AppCompatSpinner(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
}
public class AppCompatTextView extends android.widget.TextView {
@@ -1780,9 +1832,11 @@
ctor public PopupMenu(android.content.Context, android.view.View, int, int, int);
method public void dismiss();
method public android.view.View.OnTouchListener getDragToOpenListener();
+ method public int getGravity();
method public android.view.Menu getMenu();
method public android.view.MenuInflater getMenuInflater();
method public void inflate(int);
+ method public void setGravity(int);
method public void setOnDismissListener(android.support.v7.widget.PopupMenu.OnDismissListener);
method public void setOnMenuItemClickListener(android.support.v7.widget.PopupMenu.OnMenuItemClickListener);
method public void show();
@@ -1887,6 +1941,11 @@
method public void setTrackResource(int);
}
+ public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
+ method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
+ method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+ }
+
public class Toolbar extends android.view.ViewGroup {
ctor public Toolbar(android.content.Context);
ctor public Toolbar(android.content.Context, android.util.AttributeSet);
@@ -1902,6 +1961,7 @@
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
@@ -1922,6 +1982,7 @@
method public void setNavigationIcon(android.graphics.drawable.Drawable);
method public void setNavigationOnClickListener(android.view.View.OnClickListener);
method public void setOnMenuItemClickListener(android.support.v7.widget.Toolbar.OnMenuItemClickListener);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public void setSubtitle(int);
method public void setSubtitle(java.lang.CharSequence);
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index bbb2fd1..6313298 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -12,7 +12,7 @@
sourceSets {
main.manifest.srcFile 'AndroidManifest.xml'
main.java.srcDir 'src'
- main.res.srcDir 'res'
+ main.res.srcDirs 'res', 'res-public'
main.assets.srcDir 'assets'
main.resources.srcDir 'src'
diff --git a/v7/appcompat/res-public/values/public_attrs.xml b/v7/appcompat/res-public/values/public_attrs.xml
new file mode 100644
index 0000000..3db510d
--- /dev/null
+++ b/v7/appcompat/res-public/values/public_attrs.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Definitions of attributes to be exposed as public -->
+<resources>
+ <public type="attr" name="actionBarDivider"/>
+ <public type="attr" name="actionBarItemBackground"/>
+ <public type="attr" name="actionBarPopupTheme"/>
+ <public type="attr" name="actionBarSize"/>
+ <public type="attr" name="actionBarSplitStyle"/>
+ <public type="attr" name="actionBarStyle"/>
+ <public type="attr" name="actionBarTabBarStyle"/>
+ <public type="attr" name="actionBarTabStyle"/>
+ <public type="attr" name="actionBarTabTextStyle"/>
+ <public type="attr" name="actionBarTheme"/>
+ <public type="attr" name="actionBarWidgetTheme"/>
+ <public type="attr" name="actionButtonStyle"/>
+ <public type="attr" name="actionDropDownStyle"/>
+ <public type="attr" name="actionLayout"/>
+ <public type="attr" name="actionMenuTextAppearance"/>
+ <public type="attr" name="actionMenuTextColor"/>
+ <public type="attr" name="actionModeBackground"/>
+ <public type="attr" name="actionModeCloseButtonStyle"/>
+ <public type="attr" name="actionModeCloseDrawable"/>
+ <public type="attr" name="actionModeCopyDrawable"/>
+ <public type="attr" name="actionModeCutDrawable"/>
+ <public type="attr" name="actionModeFindDrawable"/>
+ <public type="attr" name="actionModePasteDrawable"/>
+ <public type="attr" name="actionModeSelectAllDrawable"/>
+ <public type="attr" name="actionModeShareDrawable"/>
+ <public type="attr" name="actionModeSplitBackground"/>
+ <public type="attr" name="actionModeStyle"/>
+ <public type="attr" name="actionModeWebSearchDrawable"/>
+ <public type="attr" name="actionOverflowButtonStyle"/>
+ <public type="attr" name="actionOverflowMenuStyle"/>
+ <public type="attr" name="actionProviderClass"/>
+ <public type="attr" name="actionViewClass"/>
+ <public type="attr" name="alertDialogStyle"/>
+ <public type="attr" name="alertDialogTheme"/>
+ <public type="attr" name="autoCompleteTextViewStyle"/>
+ <public type="attr" name="background"/>
+ <public type="attr" name="backgroundSplit"/>
+ <public type="attr" name="backgroundStacked"/>
+ <public type="attr" name="backgroundTint"/>
+ <public type="attr" name="backgroundTintMode"/>
+ <public type="attr" name="barSize"/>
+ <public type="attr" name="borderlessButtonStyle"/>
+ <public type="attr" name="buttonBarButtonStyle"/>
+ <public type="attr" name="buttonBarNegativeButtonStyle"/>
+ <public type="attr" name="buttonBarNeutralButtonStyle"/>
+ <public type="attr" name="buttonBarPositiveButtonStyle"/>
+ <public type="attr" name="buttonBarStyle"/>
+ <public type="attr" name="buttonStyle"/>
+ <public type="attr" name="buttonStyleSmall"/>
+ <public type="attr" name="buttonTint"/>
+ <public type="attr" name="buttonTintMode"/>
+ <public type="attr" name="checkboxStyle"/>
+ <public type="attr" name="checkedTextViewStyle"/>
+ <public type="attr" name="closeIcon"/>
+ <public type="attr" name="closeItemLayout"/>
+ <public type="attr" name="collapseContentDescription"/>
+ <public type="attr" name="collapseIcon"/>
+ <public type="attr" name="color"/>
+ <public type="attr" name="colorAccent"/>
+ <public type="attr" name="colorButtonNormal"/>
+ <public type="attr" name="colorControlActivated"/>
+ <public type="attr" name="colorControlHighlight"/>
+ <public type="attr" name="colorControlNormal"/>
+ <public type="attr" name="colorPrimary"/>
+ <public type="attr" name="colorPrimaryDark"/>
+ <public type="attr" name="colorSwitchThumbNormal"/>
+ <public type="attr" name="commitIcon"/>
+ <public type="attr" name="contentInsetEnd"/>
+ <public type="attr" name="contentInsetLeft"/>
+ <public type="attr" name="contentInsetRight"/>
+ <public type="attr" name="contentInsetStart"/>
+ <public type="attr" name="customNavigationLayout"/>
+ <public type="attr" name="dialogPreferredPadding"/>
+ <public type="attr" name="dialogTheme"/>
+ <public type="attr" name="displayOptions"/>
+ <public type="attr" name="divider"/>
+ <public type="attr" name="dividerHorizontal"/>
+ <public type="attr" name="dividerPadding"/>
+ <public type="attr" name="dividerVertical"/>
+ <public type="attr" name="drawableSize"/>
+ <public type="attr" name="drawerArrowStyle"/>
+ <public type="attr" name="dropdownListPreferredItemHeight"/>
+ <public type="attr" name="dropDownListViewStyle"/>
+ <public type="attr" name="editTextBackground"/>
+ <public type="attr" name="editTextColor"/>
+ <public type="attr" name="editTextStyle"/>
+ <public type="attr" name="elevation"/>
+ <public type="attr" name="gapBetweenBars"/>
+ <public type="attr" name="goIcon"/>
+ <public type="attr" name="height"/>
+ <public type="attr" name="hideOnContentScroll"/>
+ <public type="attr" name="homeAsUpIndicator"/>
+ <public type="attr" name="homeLayout"/>
+ <public type="attr" name="icon"/>
+ <public type="attr" name="iconifiedByDefault"/>
+ <public type="attr" name="indeterminateProgressStyle"/>
+ <public type="attr" name="isLightTheme"/>
+ <public type="attr" name="itemPadding"/>
+ <public type="attr" name="layout"/>
+ <public type="attr" name="listChoiceBackgroundIndicator"/>
+ <public type="attr" name="listDividerAlertDialog"/>
+ <public type="attr" name="listPopupWindowStyle"/>
+ <public type="attr" name="listPreferredItemHeight"/>
+ <public type="attr" name="listPreferredItemHeightLarge"/>
+ <public type="attr" name="listPreferredItemHeightSmall"/>
+ <public type="attr" name="listPreferredItemPaddingLeft"/>
+ <public type="attr" name="listPreferredItemPaddingRight"/>
+ <public type="attr" name="logo"/>
+ <public type="attr" name="logoDescription"/>
+ <public type="attr" name="measureWithLargestChild"/>
+ <public type="attr" name="middleBarArrowSize"/>
+ <public type="attr" name="navigationContentDescription"/>
+ <public type="attr" name="navigationIcon"/>
+ <public type="attr" name="navigationMode"/>
+ <public type="attr" name="overlapAnchor"/>
+ <public type="attr" name="paddingEnd"/>
+ <public type="attr" name="paddingStart"/>
+ <public type="attr" name="panelBackground"/>
+ <public type="attr" name="popupMenuStyle"/>
+ <public type="attr" name="popupTheme"/>
+ <public type="attr" name="popupWindowStyle"/>
+ <public type="attr" name="preserveIconSpacing"/>
+ <public type="attr" name="progressBarPadding"/>
+ <public type="attr" name="progressBarStyle"/>
+ <public type="attr" name="prompt"/>
+ <public type="attr" name="queryBackground"/>
+ <public type="attr" name="queryHint"/>
+ <public type="attr" name="radioButtonStyle"/>
+ <public type="attr" name="ratingBarStyle"/>
+ <public type="attr" name="searchHintIcon"/>
+ <public type="attr" name="searchIcon"/>
+ <public type="attr" name="searchViewStyle"/>
+ <public type="attr" name="selectableItemBackground"/>
+ <public type="attr" name="selectableItemBackgroundBorderless"/>
+ <public type="attr" name="showAsAction"/>
+ <public type="attr" name="showDividers"/>
+ <public type="attr" name="showText"/>
+ <public type="attr" name="spinBars"/>
+ <public type="attr" name="spinnerDropDownItemStyle"/>
+ <public type="attr" name="spinnerMode"/>
+ <public type="attr" name="spinnerStyle"/>
+ <public type="attr" name="splitTrack"/>
+ <public type="attr" name="submitBackground"/>
+ <public type="attr" name="subtitle"/>
+ <public type="attr" name="subtitleTextAppearance"/>
+ <public type="attr" name="subtitleTextColor"/>
+ <public type="attr" name="subtitleTextStyle"/>
+ <public type="attr" name="suggestionRowLayout"/>
+ <public type="attr" name="switchMinWidth"/>
+ <public type="attr" name="switchPadding"/>
+ <public type="attr" name="switchStyle"/>
+ <public type="attr" name="switchTextAppearance"/>
+ <public type="attr" name="textAllCaps"/>
+ <public type="attr" name="textAppearanceLargePopupMenu"/>
+ <public type="attr" name="textAppearanceListItem"/>
+ <public type="attr" name="textAppearanceListItemSmall"/>
+ <public type="attr" name="textAppearanceSearchResultSubtitle"/>
+ <public type="attr" name="textAppearanceSearchResultTitle"/>
+ <public type="attr" name="textAppearanceSmallPopupMenu"/>
+ <public type="attr" name="textColorAlertDialogListItem"/>
+ <public type="attr" name="theme"/>
+ <public type="attr" name="thickness"/>
+ <public type="attr" name="thumbTextPadding"/>
+ <public type="attr" name="title"/>
+ <public type="attr" name="titleMarginBottom"/>
+ <public type="attr" name="titleMarginEnd"/>
+ <public type="attr" name="titleMargins"/>
+ <public type="attr" name="titleMarginStart"/>
+ <public type="attr" name="titleMarginTop"/>
+ <public type="attr" name="titleTextAppearance"/>
+ <public type="attr" name="titleTextColor"/>
+ <public type="attr" name="titleTextStyle"/>
+ <public type="attr" name="toolbarNavigationButtonStyle"/>
+ <public type="attr" name="toolbarStyle"/>
+ <public type="attr" name="topBottomBarArrowSize"/>
+ <public type="attr" name="track"/>
+ <public type="attr" name="voiceIcon"/>
+ <public type="attr" name="windowActionBar"/>
+ <public type="attr" name="windowActionBarOverlay"/>
+ <public type="attr" name="windowActionModeOverlay"/>
+ <public type="attr" name="windowNoTitle"/>
+</resources>
diff --git a/v7/appcompat/res-public/values/public_layouts.xml b/v7/appcompat/res-public/values/public_layouts.xml
new file mode 100644
index 0000000..1c50667
--- /dev/null
+++ b/v7/appcompat/res-public/values/public_layouts.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Definitions of layouts to be exposed as public -->
+<resources>
+ <public type="layout" name="support_simple_spinner_dropdown_item"/>
+</resources>
diff --git a/v7/appcompat/res-public/values/public_styles.xml b/v7/appcompat/res-public/values/public_styles.xml
new file mode 100644
index 0000000..2c04266
--- /dev/null
+++ b/v7/appcompat/res-public/values/public_styles.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Definitions of styles to be exposed as public -->
+<resources>
+ <public type="style" name="TextAppearance.AppCompat"/>
+ <public type="style" name="TextAppearance.AppCompat.Body1"/>
+ <public type="style" name="TextAppearance.AppCompat.Body2"/>
+ <public type="style" name="TextAppearance.AppCompat.Button"/>
+ <public type="style" name="TextAppearance.AppCompat.Caption"/>
+ <public type="style" name="TextAppearance.AppCompat.Display1"/>
+ <public type="style" name="TextAppearance.AppCompat.Display2"/>
+ <public type="style" name="TextAppearance.AppCompat.Display3"/>
+ <public type="style" name="TextAppearance.AppCompat.Display4"/>
+ <public type="style" name="TextAppearance.AppCompat.Headline"/>
+ <public type="style" name="TextAppearance.AppCompat.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Large"/>
+ <public type="style" name="TextAppearance.AppCompat.Large.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Light.SearchResult.Subtitle"/>
+ <public type="style" name="TextAppearance.AppCompat.Light.SearchResult.Title"/>
+ <public type="style" name="TextAppearance.AppCompat.Light.Widget.PopupMenu.Large"/>
+ <public type="style" name="TextAppearance.AppCompat.Light.Widget.PopupMenu.Small"/>
+ <public type="style" name="TextAppearance.AppCompat.Medium"/>
+ <public type="style" name="TextAppearance.AppCompat.Medium.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Menu"/>
+ <public type="style" name="TextAppearance.AppCompat.SearchResult.Subtitle"/>
+ <public type="style" name="TextAppearance.AppCompat.SearchResult.Title"/>
+ <public type="style" name="TextAppearance.AppCompat.Small"/>
+ <public type="style" name="TextAppearance.AppCompat.Small.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Subhead"/>
+ <public type="style" name="TextAppearance.AppCompat.Subhead.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Title"/>
+ <public type="style" name="TextAppearance.AppCompat.Title.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionBar.Menu"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionBar.Subtitle"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionBar.Title"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Subtitle"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Subtitle.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Title"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Title.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.Button"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.Button.Inverse"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.DropDownItem"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.PopupMenu.Large"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.PopupMenu.Small"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.Switch"/>
+ <public type="style" name="TextAppearance.AppCompat.Widget.TextView.SpinnerItem"/>
+ <public type="style" name="Theme.AppCompat"/>
+ <public type="style" name="Theme.AppCompat.DayNight"/>
+ <public type="style" name="Theme.AppCompat.DayNight.DarkActionBar"/>
+ <public type="style" name="Theme.AppCompat.DayNight.Dialog"/>
+ <public type="style" name="Theme.AppCompat.DayNight.Dialog.Alert"/>
+ <public type="style" name="Theme.AppCompat.DayNight.Dialog.MinWidth"/>
+ <public type="style" name="Theme.AppCompat.DayNight.DialogWhenLarge"/>
+ <public type="style" name="Theme.AppCompat.DayNight.NoActionBar"/>
+ <public type="style" name="Theme.AppCompat.Dialog"/>
+ <public type="style" name="Theme.AppCompat.Dialog.Alert"/>
+ <public type="style" name="Theme.AppCompat.Dialog.MinWidth"/>
+ <public type="style" name="Theme.AppCompat.DialogWhenLarge"/>
+ <public type="style" name="Theme.AppCompat.Light"/>
+ <public type="style" name="Theme.AppCompat.Light.DarkActionBar"/>
+ <public type="style" name="Theme.AppCompat.Light.Dialog"/>
+ <public type="style" name="Theme.AppCompat.Light.Dialog.Alert"/>
+ <public type="style" name="Theme.AppCompat.Light.Dialog.MinWidth"/>
+ <public type="style" name="Theme.AppCompat.Light.DialogWhenLarge"/>
+ <public type="style" name="Theme.AppCompat.Light.NoActionBar"/>
+ <public type="style" name="Theme.AppCompat.NoActionBar"/>
+ <public type="style" name="ThemeOverlay.AppCompat"/>
+ <public type="style" name="ThemeOverlay.AppCompat.ActionBar"/>
+ <public type="style" name="ThemeOverlay.AppCompat.Dark"/>
+ <public type="style" name="ThemeOverlay.AppCompat.Dark.ActionBar"/>
+ <public type="style" name="ThemeOverlay.AppCompat.Light"/>
+ <public type="style" name="Widget.AppCompat.ActionBar"/>
+ <public type="style" name="Widget.AppCompat.ActionBar.Solid"/>
+ <public type="style" name="Widget.AppCompat.ActionBar.TabBar"/>
+ <public type="style" name="Widget.AppCompat.ActionBar.TabText"/>
+ <public type="style" name="Widget.AppCompat.ActionBar.TabView"/>
+ <public type="style" name="Widget.AppCompat.ActionButton"/>
+ <public type="style" name="Widget.AppCompat.ActionButton.CloseMode"/>
+ <public type="style" name="Widget.AppCompat.ActionButton.Overflow"/>
+ <public type="style" name="Widget.AppCompat.ActionMode"/>
+ <public type="style" name="Widget.AppCompat.AutoCompleteTextView"/>
+ <public type="style" name="Widget.AppCompat.Button"/>
+ <public type="style" name="Widget.AppCompat.ButtonBar"/>
+ <public type="style" name="Widget.AppCompat.ButtonBar.AlertDialog"/>
+ <public type="style" name="Widget.AppCompat.Button.Borderless"/>
+ <public type="style" name="Widget.AppCompat.Button.Borderless.Colored"/>
+ <public type="style" name="Widget.AppCompat.Button.ButtonBar.AlertDialog"/>
+ <public type="style" name="Widget.AppCompat.Button.Colored"/>
+ <public type="style" name="Widget.AppCompat.Button.Small"/>
+ <public type="style" name="Widget.AppCompat.CompoundButton.CheckBox"/>
+ <public type="style" name="Widget.AppCompat.CompoundButton.RadioButton"/>
+ <public type="style" name="Widget.AppCompat.CompoundButton.Switch"/>
+ <public type="style" name="Widget.AppCompat.DrawerArrowToggle"/>
+ <public type="style" name="Widget.AppCompat.DropDownItem.Spinner"/>
+ <public type="style" name="Widget.AppCompat.EditText"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.Solid"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.Solid.Inverse"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.TabBar"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.TabBar.Inverse"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.TabText"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.TabText.Inverse"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.TabView"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionBar.TabView.Inverse"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionButton"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionButton.CloseMode"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionButton.Overflow"/>
+ <public type="style" name="Widget.AppCompat.Light.ActionMode.Inverse"/>
+ <public type="style" name="Widget.AppCompat.Light.AutoCompleteTextView"/>
+ <public type="style" name="Widget.AppCompat.Light.DropDownItem.Spinner"/>
+ <public type="style" name="Widget.AppCompat.Light.ListPopupWindow"/>
+ <public type="style" name="Widget.AppCompat.Light.ListView.DropDown"/>
+ <public type="style" name="Widget.AppCompat.Light.PopupMenu"/>
+ <public type="style" name="Widget.AppCompat.Light.PopupMenu.Overflow"/>
+ <public type="style" name="Widget.AppCompat.Light.SearchView"/>
+ <public type="style" name="Widget.AppCompat.Light.Spinner.DropDown.ActionBar"/>
+ <public type="style" name="Widget.AppCompat.ListPopupWindow"/>
+ <public type="style" name="Widget.AppCompat.ListView"/>
+ <public type="style" name="Widget.AppCompat.ListView.DropDown"/>
+ <public type="style" name="Widget.AppCompat.ListView.Menu"/>
+ <public type="style" name="Widget.AppCompat.PopupMenu"/>
+ <public type="style" name="Widget.AppCompat.PopupMenu.Overflow"/>
+ <public type="style" name="Widget.AppCompat.PopupWindow"/>
+ <public type="style" name="Widget.AppCompat.ProgressBar"/>
+ <public type="style" name="Widget.AppCompat.ProgressBar.Horizontal"/>
+ <public type="style" name="Widget.AppCompat.RatingBar"/>
+ <public type="style" name="Widget.AppCompat.SearchView"/>
+ <public type="style" name="Widget.AppCompat.SearchView.ActionBar"/>
+ <public type="style" name="Widget.AppCompat.Spinner"/>
+ <public type="style" name="Widget.AppCompat.Spinner.DropDown"/>
+ <public type="style" name="Widget.AppCompat.Spinner.DropDown.ActionBar"/>
+ <public type="style" name="Widget.AppCompat.Spinner.Underlined"/>
+ <public type="style" name="Widget.AppCompat.TextView.SpinnerItem"/>
+ <public type="style" name="Widget.AppCompat.Toolbar"/>
+ <public type="style" name="Widget.AppCompat.Toolbar.Button.Navigation"/>
+</resources>
diff --git a/v7/appcompat/res/color-v23/abc_color_highlight_material.xml b/v7/appcompat/res/color-v23/abc_color_highlight_material.xml
new file mode 100644
index 0000000..8d53611
--- /dev/null
+++ b/v7/appcompat/res/color-v23/abc_color_highlight_material.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true"
+ android:state_enabled="true"
+ android:alpha="@dimen/highlight_alpha_material_colored"
+ android:color="?android:attr/colorControlActivated" />
+ <item android:color="?android:attr/colorControlHighlight" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-hdpi/abc_text_cursor_mtrl_alpha.9.png b/v7/appcompat/res/drawable-hdpi/abc_text_cursor_mtrl_alpha.9.png
deleted file mode 100644
index 5e0bf84..0000000
--- a/v7/appcompat/res/drawable-hdpi/abc_text_cursor_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/v7/appcompat/res/drawable-mdpi/abc_text_cursor_mtrl_alpha.9.png b/v7/appcompat/res/drawable-mdpi/abc_text_cursor_mtrl_alpha.9.png
deleted file mode 100644
index 36348a8..0000000
--- a/v7/appcompat/res/drawable-mdpi/abc_text_cursor_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/v7/appcompat/res/drawable-v21/abc_action_bar_item_background_material.xml b/v7/appcompat/res/drawable-v21/abc_action_bar_item_background_material.xml
new file mode 100644
index 0000000..595c56c
--- /dev/null
+++ b/v7/appcompat/res/drawable-v21/abc_action_bar_item_background_material.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight"/>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-v21/abc_btn_colored_material.xml b/v7/appcompat/res/drawable-v21/abc_btn_colored_material.xml
new file mode 100644
index 0000000..10251aa
--- /dev/null
+++ b/v7/appcompat/res/drawable-v21/abc_btn_colored_material.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="@dimen/abc_button_inset_horizontal_material"
+ android:insetTop="@dimen/abc_button_inset_vertical_material"
+ android:insetRight="@dimen/abc_button_inset_horizontal_material"
+ android:insetBottom="@dimen/abc_button_inset_vertical_material">
+ <ripple android:color="?android:attr/colorControlHighlight">
+ <item>
+ <!-- As we can't use themed ColorStateLists in L, we'll use a Drawable selector which
+ changes the shape's fill color. -->
+ <selector>
+ <item android:state_enabled="false">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/abc_control_corner_material"/>
+ <solid android:color="?android:attr/colorButtonNormal"/>
+ <padding android:left="@dimen/abc_button_padding_horizontal_material"
+ android:top="@dimen/abc_button_padding_vertical_material"
+ android:right="@dimen/abc_button_padding_horizontal_material"
+ android:bottom="@dimen/abc_button_padding_vertical_material"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/abc_control_corner_material"/>
+ <solid android:color="?android:attr/colorAccent"/>
+ <padding android:left="@dimen/abc_button_padding_horizontal_material"
+ android:top="@dimen/abc_button_padding_vertical_material"
+ android:right="@dimen/abc_button_padding_horizontal_material"
+ android:bottom="@dimen/abc_button_padding_vertical_material"/>
+ </shape>
+ </item>
+ </selector>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-v23/abc_control_background_material.xml b/v7/appcompat/res/drawable-v23/abc_control_background_material.xml
new file mode 100644
index 0000000..0b54039
--- /dev/null
+++ b/v7/appcompat/res/drawable-v23/abc_control_background_material.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/abc_color_highlight_material"
+ android:radius="20dp" />
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-xhdpi/abc_text_cursor_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xhdpi/abc_text_cursor_mtrl_alpha.9.png
deleted file mode 100644
index 666b10a..0000000
--- a/v7/appcompat/res/drawable-xhdpi/abc_text_cursor_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/v7/appcompat/res/drawable-xxhdpi/abc_text_cursor_mtrl_alpha.9.png b/v7/appcompat/res/drawable-xxhdpi/abc_text_cursor_mtrl_alpha.9.png
deleted file mode 100644
index 08ee2b4..0000000
--- a/v7/appcompat/res/drawable-xxhdpi/abc_text_cursor_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/v7/appcompat/res/drawable/abc_btn_colored_material.xml b/v7/appcompat/res/drawable/abc_btn_colored_material.xml
new file mode 100644
index 0000000..ec93b8b
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_btn_colored_material.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Used as the canonical button shape. -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/abc_btn_default_mtrl_shape" />
+</layer-list>
diff --git a/v7/appcompat/res/drawable/abc_text_cursor_material.xml b/v7/appcompat/res/drawable/abc_text_cursor_material.xml
new file mode 100644
index 0000000..885670c
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_text_cursor_material.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <size android:height="2dp"
+ android:width="2dp"/>
+ <solid android:color="@android:color/white"/>
+</shape>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-az-rAZ/strings.xml b/v7/appcompat/res/values-az-rAZ/strings.xml
new file mode 100644
index 0000000..a39f5f4
--- /dev/null
+++ b/v7/appcompat/res/values-az-rAZ/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="abc_action_mode_done" msgid="4076576682505996667">"Hazırdır"</string>
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Evə get"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Yuxarı get"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Daha çox seçim"</string>
+ <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"Dağıt"</string>
+ <string name="abc_action_bar_home_description_format" msgid="1397052879051804371">"%1$s, %2$s"</string>
+ <string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Axtarış"</string>
+ <string name="abc_search_hint" msgid="7723749260725869598">"Axtarış..."</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Axtarış sorğusu"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Sorğunu təmizlə"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Sorğunu göndərin"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Səsli axtarış"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Tətbiq seçin"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Hamısına baxın"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for abc_shareactionprovider_share_with_application (7165123711973476752) -->
+ <skip />
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Bununla paylaşın"</string>
+ <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+</resources>
diff --git a/v7/appcompat/res/values-gu-rIN/strings.xml b/v7/appcompat/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000..b77acd3
--- /dev/null
+++ b/v7/appcompat/res/values-gu-rIN/strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="abc_action_mode_done" msgid="4076576682505996667">"થઈ ગયું"</string>
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"હોમ પર નેવિગેટ કરો"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ઉપર નેવિગેટ કરો"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"વધુ વિકલ્પો"</string>
+ <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"સંકુચિત કરો"</string>
+ <string name="abc_action_bar_home_description_format" msgid="1397052879051804371">"%1$s, %2$s"</string>
+ <string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"શોધો"</string>
+ <string name="abc_search_hint" msgid="7723749260725869598">"શોધો…"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"શોધ ક્વેરી"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ક્વેરી સાફ કરો"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ક્વેરી સબમિટ કરો"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"વૉઇસ શોધ"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"એક એપ્લિકેશન પસંદ કરો"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"બધું જુઓ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s સાથે શેર કરો"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"આની સાથે શેર કરો"</string>
+ <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+</resources>
diff --git a/v7/appcompat/res/values-night/themes_daynight.xml b/v7/appcompat/res/values-night/themes_daynight.xml
new file mode 100644
index 0000000..965d355
--- /dev/null
+++ b/v7/appcompat/res/values-night/themes_daynight.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <!-- Material theme (day/night vesion) for activities. -->
+ <style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat" />
+
+ <!-- Variant of AppCompat.DayNight that has a solid (opaque) action bar
+ with an inverse color profile. The dark action bar sharply stands out against
+ the light content (when applicable). -->
+ <style name="Theme.AppCompat.DayNight.DarkActionBar" parent="Theme.AppCompat" />
+
+ <!-- Variant of AppCompat.DayNight with no action bar. -->
+ <style name="Theme.AppCompat.DayNight.NoActionBar" parent="Theme.AppCompat.NoActionBar" />
+
+ <!-- Material theme (day/night vesion) for dialog windows and activities,
+ which is used by the {@code android.support.v7.app.Dialog} class. This changes
+ the window to be floating (not fill the entire screen), and puts a
+ frame around its contents. You can set this theme on an activity if
+ you would like to make an activity that looks like a Dialog. -->
+ <style name="Theme.AppCompat.DayNight.Dialog" parent="Theme.AppCompat.Dialog" />
+
+ <!-- Variant of Theme.AppCompat.DayNight.Dialog that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.AppCompat.DayNight.Dialog.MinWidth" parent="Theme.AppCompat.Dialog.MinWidth" />
+
+ <!-- Theme for a window that will be displayed either full-screen on
+ smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.AppCompat.DayNight.DialogWhenLarge" parent="Theme.AppCompat.DialogWhenLarge" />
+
+ <!-- Material user theme for alert dialog windows, which is used by the
+ {@code android.support.v7.app.AlertDialog} class. -->
+ <style name="Theme.AppCompat.DayNight.Dialog.Alert" parent="Theme.AppCompat.Dialog.Alert" />
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-pa-rIN/strings.xml b/v7/appcompat/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000..af87fdf
--- /dev/null
+++ b/v7/appcompat/res/values-pa-rIN/strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="abc_action_mode_done" msgid="4076576682505996667">"ਹੋ ਗਿਆ"</string>
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ਹੋਮ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ਉੱਪਰ ਨੈਵੀਗੇਟ ਕਰੋ"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ਹੋਰ ਚੋਣਾਂ"</string>
+ <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"ਨਸ਼ਟ ਕਰੋ"</string>
+ <string name="abc_action_bar_home_description_format" msgid="1397052879051804371">"%1$s, %2$s"</string>
+ <string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ਖੋਜੋ"</string>
+ <string name="abc_search_hint" msgid="7723749260725869598">"ਖੋਜ…"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"ਸਵਾਲ ਖੋਜੋ"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ਸਵਾਲ ਹਟਾਓ"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ਸਵਾਲ ਪ੍ਰਸਤੁਤ ਕਰੋ"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"ਵੌਇਸ ਖੋਜ"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"ਇੱਕ ਐਪ ਚੁਣੋ"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"ਸਭ ਦੇਖੋ"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"%s ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ਇਸ ਨਾਲ ਸ਼ੇਅਰ ਕਰੋ"</string>
+ <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+</resources>
diff --git a/v7/appcompat/res/values-sq-rAL/strings.xml b/v7/appcompat/res/values-sq-rAL/strings.xml
new file mode 100644
index 0000000..68689a6
--- /dev/null
+++ b/v7/appcompat/res/values-sq-rAL/strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="abc_action_mode_done" msgid="4076576682505996667">"U krye!"</string>
+ <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Orientohu për në shtëpi"</string>
+ <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Ngjitu lart"</string>
+ <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Opsione të tjera"</string>
+ <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"Shpalos"</string>
+ <string name="abc_action_bar_home_description_format" msgid="1397052879051804371">"%1$s, %2$s"</string>
+ <string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"Kërko"</string>
+ <string name="abc_search_hint" msgid="7723749260725869598">"Kërko..."</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Kërko pyetjen"</string>
+ <string name="abc_searchview_description_clear" msgid="3691816814315814921">"Pastro pyetjen"</string>
+ <string name="abc_searchview_description_submit" msgid="8928215447528550784">"Dërgo pyetjen"</string>
+ <string name="abc_searchview_description_voice" msgid="893419373245838918">"Kërkim me zë"</string>
+ <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Zgjidh një aplikacion"</string>
+ <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Shikoji të gjitha"</string>
+ <string name="abc_shareactionprovider_share_with_application" msgid="7165123711973476752">"Shpërnda publikisht me %s"</string>
+ <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Shpërnda publikisht me"</string>
+ <string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
+</resources>
diff --git a/v7/appcompat/res/values-v11/styles_base.xml b/v7/appcompat/res/values-v11/styles_base.xml
index 0bbf7e3..f651320 100644
--- a/v7/appcompat/res/values-v11/styles_base.xml
+++ b/v7/appcompat/res/values-v11/styles_base.xml
@@ -21,11 +21,7 @@
variants are for direct use or use as parent styles by the app. -->
<eat-comment/>
- <style name="Base.Widget.AppCompat.Spinner" parent="android:Widget.Holo.Spinner">
- <item name="android:background">@drawable/abc_spinner_mtrl_am_alpha</item>
- <item name="android:dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
- <item name="android:popupBackground">@drawable/abc_popup_background_mtrl_mult</item>
- </style>
+ <style name="Platform.Widget.AppCompat.Spinner" parent="android:Widget.Holo.Spinner" />
<!-- Progress Bar -->
diff --git a/v7/appcompat/res/values-v11/themes_base.xml b/v7/appcompat/res/values-v11/themes_base.xml
index 2ca5b6f..c2b9aeb 100644
--- a/v7/appcompat/res/values-v11/themes_base.xml
+++ b/v7/appcompat/res/values-v11/themes_base.xml
@@ -36,8 +36,8 @@
<item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
<!-- Window colors -->
- <item name="android:colorForeground">@color/bright_foreground_material_dark</item>
- <item name="android:colorForegroundInverse">@color/bright_foreground_material_light</item>
+ <item name="android:colorForeground">@color/foreground_material_dark</item>
+ <item name="android:colorForegroundInverse">@color/foreground_material_light</item>
<item name="android:colorBackground">@color/background_material_dark</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_dark</item>
<item name="android:disabledAlpha">@dimen/abc_disabled_alpha_material_dark</item>
@@ -88,8 +88,8 @@
<item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
<!-- Window colors -->
- <item name="android:colorForeground">@color/bright_foreground_material_light</item>
- <item name="android:colorForegroundInverse">@color/bright_foreground_material_dark</item>
+ <item name="android:colorForeground">@color/foreground_material_light</item>
+ <item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
<item name="android:colorBackground">@color/background_material_light</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
<item name="android:disabledAlpha">@dimen/abc_disabled_alpha_material_light</item>
diff --git a/v7/appcompat/res/values-v12/styles_base.xml b/v7/appcompat/res/values-v12/styles_base.xml
index 6d87337..f7965a4 100644
--- a/v7/appcompat/res/values-v12/styles_base.xml
+++ b/v7/appcompat/res/values-v12/styles_base.xml
@@ -19,13 +19,13 @@
<style name="Base.Widget.AppCompat.EditText" parent="Base.V12.Widget.AppCompat.EditText" />
<style name="Base.V12.Widget.AppCompat.EditText" parent="Base.V7.Widget.AppCompat.EditText">
- <item name="android:textCursorDrawable">@drawable/abc_text_cursor_mtrl_alpha</item>
+ <item name="android:textCursorDrawable">@drawable/abc_text_cursor_material</item>
</style>
<style name="Base.Widget.AppCompat.AutoCompleteTextView" parent="Base.V12.Widget.AppCompat.AutoCompleteTextView" />
<style name="Base.V12.Widget.AppCompat.AutoCompleteTextView" parent="Base.V7.Widget.AppCompat.AutoCompleteTextView">
- <item name="android:textCursorDrawable">@drawable/abc_text_cursor_mtrl_alpha</item>
+ <item name="android:textCursorDrawable">@drawable/abc_text_cursor_material</item>
</style>
</resources>
diff --git a/v7/appcompat/res/values-v21/styles_base.xml b/v7/appcompat/res/values-v21/styles_base.xml
index 241cb04..47681f2 100644
--- a/v7/appcompat/res/values-v21/styles_base.xml
+++ b/v7/appcompat/res/values-v21/styles_base.xml
@@ -115,12 +115,6 @@
<style name="Base.Widget.AppCompat.Spinner.Underlined" parent="android:Widget.Material.Spinner.Underlined" />
- <style name="Base.Widget.AppCompat.Spinner.DropDown.ActionBar" parent="android:Widget.Material.Spinner">
- <item name="spinnerMode">dropdown</item>
- <item name="disableChildrenWhenDisabled">true</item>
- <item name="popupPromptView">@layout/abc_simple_dropdown_hint</item>
- </style>
-
<style name="Base.Widget.AppCompat.ListView" parent="android:Widget.Material.ListView" />
<style name="Base.Widget.AppCompat.ListView.Menu" />
diff --git a/v7/appcompat/res/values-v21/styles_base_text.xml b/v7/appcompat/res/values-v21/styles_base_text.xml
index 241a91b..b66f7cf 100644
--- a/v7/appcompat/res/values-v21/styles_base_text.xml
+++ b/v7/appcompat/res/values-v21/styles_base_text.xml
@@ -59,6 +59,8 @@
<style name="Base.TextAppearance.AppCompat.Button" parent="android:TextAppearance.Material.Button" />
+ <style name="Base.TextAppearance.AppCompat.Widget.Button" parent="android:TextAppearance.Material.Widget.Button" />
+
<style name="Base.TextAppearance.AppCompat.Widget.Switch" parent="android:TextAppearance.Material.Button" />
</resources>
diff --git a/v7/appcompat/res/values-v21/themes_base.xml b/v7/appcompat/res/values-v21/themes_base.xml
index 61cce2f..9d193d5 100644
--- a/v7/appcompat/res/values-v21/themes_base.xml
+++ b/v7/appcompat/res/values-v21/themes_base.xml
@@ -46,7 +46,7 @@
<!-- Action Bar styling attributes -->
<item name="actionBarSize">?android:attr/actionBarSize</item>
<item name="actionBarDivider">?android:attr/actionBarDivider</item>
- <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="actionBarItemBackground">@drawable/abc_action_bar_item_background_material</item>
<item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
<item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
<item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
@@ -95,7 +95,7 @@
<!-- Action Bar styling attributes -->
<item name="actionBarSize">?android:attr/actionBarSize</item>
<item name="actionBarDivider">?android:attr/actionBarDivider</item>
- <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+ <item name="actionBarItemBackground">@drawable/abc_action_bar_item_background_material</item>
<item name="actionButtonStyle">?android:attr/actionButtonStyle</item>
<item name="actionMenuTextColor">?android:attr/actionMenuTextColor</item>
<item name="actionMenuTextAppearance">?android:attr/actionMenuTextAppearance</item>
diff --git a/v7/appcompat/res/layout/abc_simple_dropdown_hint.xml b/v7/appcompat/res/values-v23/styles_base.xml
similarity index 65%
rename from v7/appcompat/res/layout/abc_simple_dropdown_hint.xml
rename to v7/appcompat/res/values-v23/styles_base.xml
index 8326b5c..e1c8910 100644
--- a/v7/appcompat/res/layout/abc_simple_dropdown_hint.xml
+++ b/v7/appcompat/res/values-v23/styles_base.xml
@@ -14,10 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:textAppearance="?android:attr/dropDownHintAppearance"
- android:singleLine="true"
- android:layout_margin="3dip"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
\ No newline at end of file
+
+<resources>
+
+ <style name="Base.Widget.AppCompat.Button.Colored" parent="android:Widget.Material.Button.Colored" />
+
+</resources>
diff --git a/v7/appcompat/res/layout/abc_simple_dropdown_hint.xml b/v7/appcompat/res/values-v23/styles_base_text.xml
similarity index 65%
copy from v7/appcompat/res/layout/abc_simple_dropdown_hint.xml
copy to v7/appcompat/res/values-v23/styles_base_text.xml
index 8326b5c..3fbae02 100644
--- a/v7/appcompat/res/layout/abc_simple_dropdown_hint.xml
+++ b/v7/appcompat/res/values-v23/styles_base_text.xml
@@ -14,10 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:textAppearance="?android:attr/dropDownHintAppearance"
- android:singleLine="true"
- android:layout_margin="3dip"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
\ No newline at end of file
+<resources>
+
+ <style name="Base.TextAppearance.AppCompat.Widget.Button.Inverse" parent="android:TextAppearance.Material.Widget.Button.Inverse" />
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-v23/themes_base.xml b/v7/appcompat/res/values-v23/themes_base.xml
new file mode 100644
index 0000000..becb1f2
--- /dev/null
+++ b/v7/appcompat/res/values-v23/themes_base.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <style name="Base.Theme.AppCompat" parent="Base.V23.Theme.AppCompat" />
+ <style name="Base.Theme.AppCompat.Light" parent="Base.V23.Theme.AppCompat.Light" />
+
+ <style name="Base.V23.Theme.AppCompat" parent="Base.V22.Theme.AppCompat">
+ <!-- We can use the platform drawable on v23+ -->
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+
+ <item name="controlBackground">@drawable/abc_control_background_material</item>
+ </style>
+
+ <style name="Base.V23.Theme.AppCompat.Light" parent="Base.V22.Theme.AppCompat.Light">
+ <!-- We can use the platform drawable on v23+ -->
+ <item name="actionBarItemBackground">?android:attr/actionBarItemBackground</item>
+
+ <item name="controlBackground">@drawable/abc_control_background_material</item>
+ </style>
+
+</resources>
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index a7b51c1..9b029d4 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -325,6 +325,9 @@
<!-- The color applied to framework switch thumbs in their normal state. -->
<attr name="colorSwitchThumbNormal" format="color" />
+ <!-- The background used by framework controls. -->
+ <attr name="controlBackground" format="reference" />
+
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
@@ -492,7 +495,6 @@
<attr name="paddingStart" format="dimension"/>
<!-- Sets the padding, in pixels, of the end edge; see {@link android.R.attr#padding}. -->
<attr name="paddingEnd" format="dimension"/>
-
<!-- Boolean that controls whether a view can take focus. By default the user can not
move focus to a view; by setting this attribute to true the view is
allowed to take focus. This value does not impact the behavior of
@@ -500,15 +502,16 @@
always request focus regardless of this view. It only impacts where
focus navigation will try to move focus. -->
<attr name="android:focusable" />
-
<!-- Deprecated. -->
<attr name="theme" format="reference" />
-
<!-- Specifies a theme override for a view. When a theme override is set, the
view will be inflated using a {@link android.content.Context} themed with
the specified resource. -->
<attr name="android:theme" />
+ </declare-styleable>
+ <declare-styleable name="ViewBackgroundHelper">
+ <attr name="android:background" />
<!-- Tint to apply to the background. -->
<attr name="backgroundTint" format="color" />
@@ -671,37 +674,13 @@
<declare-styleable name="Spinner">
<!-- The prompt to display when the spinner's dialog is shown. -->
- <attr name="prompt" format="reference" />
- <!-- Display mode for spinner options. -->
- <attr name="spinnerMode" format="enum">
- <!-- Spinner options will be presented to the user as a dialog window. -->
- <enum name="dialog" value="0" />
- <!-- Spinner options will be presented to the user as an inline dropdown
- anchored to the spinner widget itself. -->
- <enum name="dropdown" value="1" />
- </attr>
- <!-- List selector to use for spinnerMode="dropdown" display. -->
- <attr name="android:dropDownSelector" />
+ <attr name="android:prompt" />
+ <!-- Theme to use for the drop-down or dialog popup window. -->
+ <attr name="popupTheme" />
<!-- Background drawable to use for the dropdown in spinnerMode="dropdown". -->
<attr name="android:popupBackground" />
- <!-- Vertical offset from the spinner widget for positioning the dropdown in
- spinnerMode="dropdown". -->
- <attr name="android:dropDownVerticalOffset" />
- <!-- Horizontal offset from the spinner widget for positioning the dropdown
- in spinnerMode="dropdown". -->
- <attr name="android:dropDownHorizontalOffset" />
<!-- Width of the dropdown in spinnerMode="dropdown". -->
<attr name="android:dropDownWidth" />
- <!-- Reference to a layout to use for displaying a prompt in the dropdown for
- spinnerMode="dropdown". This layout must contain a TextView with the id
- {@code @android:id/text1} to be populated with the prompt text. -->
- <attr name="popupPromptView" format="reference" />
- <!-- Gravity setting for positioning the currently selected item. -->
- <attr name="android:gravity" />
- <!-- Whether this spinner should mark child views as enabled/disabled when
- the spinner itself is enabled/disabled. -->
- <attr name="disableChildrenWhenDisabled" format="boolean" />
- <attr name="android:background" />
</declare-styleable>
<declare-styleable name="SearchView">
@@ -837,6 +816,17 @@
<!-- Allows us to read in the minHeight attr pre-v16 -->
<attr name="android:minHeight" />
+
+ <!-- Drawable to set as the logo that appears at the starting side of
+ the Toolbar, just after the navigation button. -->
+ <attr name="logo" />
+ <!-- A content description string to describe the appearance of the
+ associated logo image. -->
+ <attr name="logoDescription" format="string" />
+ <!-- A color to apply to the title string. -->
+ <attr name="titleTextColor" format="color" />
+ <!-- A color to apply to the subtitle string. -->
+ <attr name="subtitleTextColor" format="color" />
</declare-styleable>
<declare-styleable name="PopupWindowBackgroundState">
@@ -888,6 +878,30 @@
<attr name="android:id" />
</declare-styleable>
+ <declare-styleable name="CompoundButton">
+ <attr name="android:button"/>
+ <!-- Tint to apply to the button drawable. -->
+ <attr name="buttonTint" format="color" />
+
+ <!-- Blending mode used to apply the button tint. -->
+ <attr name="buttonTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ </attr>
+ </declare-styleable>
+
<declare-styleable name="SwitchCompat">
<!-- Drawable to use as the "thumb" that switches back and forth. -->
<attr name="android:thumb" />
diff --git a/v7/appcompat/res/values/colors_material.xml b/v7/appcompat/res/values/colors_material.xml
index 6b3cca5..1470d18 100644
--- a/v7/appcompat/res/values/colors_material.xml
+++ b/v7/appcompat/res/values/colors_material.xml
@@ -17,17 +17,22 @@
<!-- Colors specific to Material themes. -->
<resources>
- <color name="background_material_dark">#ff303030</color>
- <color name="background_material_light">#ffeeeeee</color>
- <color name="background_floating_material_dark">#ff424242</color>
- <color name="background_floating_material_light">#ffeeeeee</color>
+ <color name="foreground_material_dark">@android:color/white</color>
+ <color name="foreground_material_light">@android:color/black</color>
- <color name="primary_material_dark">#ff212121</color>
- <color name="primary_material_light">#ffefefef</color>
- <color name="primary_dark_material_dark">#ff000000</color>
- <color name="primary_dark_material_light">#ff757575</color>
+ <color name="background_material_dark">@color/material_grey_850</color>
+ <color name="background_material_light">@color/material_grey_50</color>
+ <color name="background_floating_material_dark">@color/material_grey_800</color>
+ <color name="background_floating_material_light">@android:color/white</color>
- <color name="ripple_material_dark">#4dffffff</color>
+ <color name="primary_material_dark">@color/material_grey_900</color>
+ <color name="primary_material_light">@color/material_grey_100</color>
+ <color name="primary_dark_material_dark">@android:color/black</color>
+ <color name="primary_dark_material_light">@color/material_grey_600</color>
+
+ <!-- 26% white (foreground) -->
+ <color name="ripple_material_dark">#42ffffff</color>
+ <!-- 12% black (foreground) -->
<color name="ripple_material_light">#1f000000</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
@@ -63,21 +68,29 @@
<!-- TODO: This is 40% alpha on the default accent color. -->
<color name="highlighted_text_material_light">#66009688</color>
- <color name="link_text_material_dark">@color/material_deep_teal_200</color>
<color name="link_text_material_light">@color/material_deep_teal_500</color>
+ <color name="link_text_material_dark">@color/material_deep_teal_200</color>
<!-- Text & foreground colors -->
<eat-comment />
+ <!-- 87% black -->
<color name="primary_text_default_material_light">#de000000</color>
+ <!-- 54% black -->
<color name="secondary_text_default_material_light">#8a000000</color>
+ <!-- 100% white -->
<color name="primary_text_default_material_dark">#ffffffff</color>
+ <!-- 70% white -->
<color name="secondary_text_default_material_dark">#b3ffffff</color>
<item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
<item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
+ <item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
+ <item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
+ <item name="highlight_alpha_material_colored" format="float" type="dimen">0.26</item>
+
<!-- 26% of default values -->
<color name="primary_text_disabled_material_light">#39000000</color>
<color name="secondary_text_disabled_material_light">#24000000</color>
@@ -89,6 +102,14 @@
<!-- Primary & accent colors -->
<eat-comment />
+ <color name="material_grey_900">#ff212121</color>
+ <color name="material_grey_850">#ff303030</color>
+ <color name="material_grey_800">#ff424242</color>
+ <color name="material_grey_600">#ff757575</color>
+ <color name="material_grey_300">#ffe0e0e0</color>
+ <color name="material_grey_100">#fff5f5f5</color>
+ <color name="material_grey_50">#fffafafa</color>
+
<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_500">#ff009688</color>
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index 0ac20d5..7585d05 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -35,12 +35,10 @@
</style>
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title"
- parent="Base.TextAppearance.AppCompat.Widget.ActionBar.Title">
- </style>
+ parent="Base.TextAppearance.AppCompat.Widget.ActionBar.Title" />
<style name="TextAppearance.AppCompat.Widget.ActionBar.Subtitle"
- parent="Base.TextAppearance.AppCompat.Widget.ActionBar.Subtitle">
- </style>
+ parent="Base.TextAppearance.AppCompat.Widget.ActionBar.Subtitle" />
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
parent="Base.TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse">
@@ -123,7 +121,7 @@
<style name="Widget.AppCompat.Spinner.DropDown" />
- <style name="Widget.AppCompat.Spinner.DropDown.ActionBar" parent="Base.Widget.AppCompat.Spinner.DropDown.ActionBar" />
+ <style name="Widget.AppCompat.Spinner.DropDown.ActionBar" />
<!-- This style has an extra indirection to properly set RTL attributes. See styles_rtl.xml -->
<style name="Widget.AppCompat.DropDownItem.Spinner" parent="RtlOverlay.Widget.AppCompat.Search.DropDown.Text" />
@@ -214,6 +212,8 @@
<style name="Widget.AppCompat.Button.ButtonBar.AlertDialog" parent="Base.Widget.AppCompat.Button.ButtonBar.AlertDialog" />
+ <style name="Widget.AppCompat.Button.Colored" parent="Base.Widget.AppCompat.Button.Colored" />
+
<style name="Widget.AppCompat.ButtonBar" parent="Base.Widget.AppCompat.ButtonBar" />
<style name="Widget.AppCompat.ButtonBar.AlertDialog" parent="Base.Widget.AppCompat.ButtonBar.AlertDialog" />
@@ -293,6 +293,10 @@
<style name="TextAppearance.AppCompat.Button" parent="Base.TextAppearance.AppCompat.Button" />
+ <style name="TextAppearance.AppCompat.Widget.Button" parent="Base.TextAppearance.AppCompat.Widget.Button" />
+
+ <style name="TextAppearance.AppCompat.Widget.Button.Inverse" parent="Base.TextAppearance.AppCompat.Widget.Button.Inverse" />
+
<style name="TextAppearance.AppCompat.Widget.Switch" parent="Base.TextAppearance.AppCompat.Widget.Switch" />
<style name="TextAppearance.AppCompat.Widget.TextView.SpinnerItem" parent="Base.TextAppearance.AppCompat.Widget.TextView.SpinnerItem" />
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index 0feb530..c1cfce1 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -73,8 +73,7 @@
</style>
<style name="Base.Widget.AppCompat.ActionButton.CloseMode">
- <item name="android:background">?attr/selectableItemBackgroundBorderless</item>
- <item name="android:minWidth">56dp</item>
+ <item name="android:background">?attr/controlBackground</item>
</style>
<style name="Base.Widget.AppCompat.ActionButton.Overflow">
@@ -138,34 +137,33 @@
<item name="closeItemLayout">@layout/abc_action_mode_close_item_material</item>
</style>
- <style name="Base.TextAppearance.AppCompat.Widget.ActionMode.Title" parent="TextAppearance.AppCompat.Title">
- <item name="android:textSize">@dimen/abc_text_size_title_material_toolbar</item>
- </style>
+ <style name="Base.TextAppearance.AppCompat.Widget.ActionMode.Title" parent="TextAppearance.AppCompat.Widget.ActionBar.Title"/>
- <style name="Base.TextAppearance.AppCompat.Widget.ActionMode.Subtitle" parent="TextAppearance.AppCompat.Subhead">
- <item name="android:textSize">@dimen/abc_text_size_subtitle_material_toolbar</item>
- </style>
+ <style name="Base.TextAppearance.AppCompat.Widget.ActionMode.Subtitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Subtitle"/>
- <style name="Base.TextAppearance.AppCompat.Widget.ActionBar.Menu" parent="android:TextAppearance.Small">
- <item name="android:textSize">12sp</item>
- <item name="android:textStyle">bold</item>
+ <style name="Base.TextAppearance.AppCompat.Widget.ActionBar.Menu" parent="TextAppearance.AppCompat.Menu">
<item name="android:textColor">?attr/actionMenuTextColor</item>
+ <item name="textAllCaps">@bool/abc_config_actionMenuItemAllCaps</item>
</style>
<style name="Base.TextAppearance.AppCompat.Widget.ActionBar.Title" parent="TextAppearance.AppCompat.Title">
<item name="android:textSize">@dimen/abc_text_size_title_material_toolbar</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="Base.TextAppearance.AppCompat.Widget.ActionBar.Subtitle" parent="TextAppearance.AppCompat.Subhead">
<item name="android:textSize">@dimen/abc_text_size_subtitle_material_toolbar</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
<style name="Base.TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" parent="TextAppearance.AppCompat.Title.Inverse">
<item name="android:textSize">@dimen/abc_text_size_title_material_toolbar</item>
+ <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
<style name="Base.TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.AppCompat.Subhead.Inverse">
<item name="android:textSize">@dimen/abc_text_size_subtitle_material_toolbar</item>
+ <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
</style>
<style name="Base.Widget.AppCompat.ProgressBar.Horizontal" parent="android:Widget.ProgressBar.Horizontal">
@@ -180,32 +178,24 @@
<!-- Spinner Widgets -->
- <style name="Base.Widget.AppCompat.Spinner" parent="android:Widget.Spinner">
+ <style name="Platform.Widget.AppCompat.Spinner" parent="android:Widget.Spinner" />
+
+ <style name="Base.Widget.AppCompat.Spinner" parent="Platform.Widget.AppCompat.Spinner">
<item name="android:background">@drawable/abc_spinner_mtrl_am_alpha</item>
+ <item name="android:popupBackground">@drawable/abc_popup_background_mtrl_mult</item>
<item name="android:dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
<item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:dropDownHorizontalOffset">0dip</item>
+ <item name="android:dropDownWidth">wrap_content</item>
+ <item name="android:clickable">true</item>
+ <item name="android:gravity">left|start|center_vertical</item>
+ <item name="overlapAnchor">true</item>
</style>
<style name="Base.Widget.AppCompat.Spinner.Underlined">
<item name="android:background">@drawable/abc_spinner_textfield_background_material</item>
</style>
- <style name="Base.Widget.AppCompat.Spinner.DropDown.ActionBar" parent="android:Widget">
- <item name="spinnerMode">dropdown</item>
-
- <item name="android:clickable">true</item>
- <item name="android:background">@drawable/abc_spinner_mtrl_am_alpha</item>
- <item name="android:dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
- <item name="android:popupBackground">@drawable/abc_popup_background_mtrl_mult</item>
- <item name="android:dropDownVerticalOffset">0dip</item>
- <item name="android:dropDownHorizontalOffset">0dip</item>
- <item name="overlapAnchor">true</item>
- <item name="android:dropDownWidth">wrap_content</item>
- <item name="popupPromptView">@layout/abc_simple_dropdown_hint</item>
- <item name="android:gravity">left|start|center_vertical</item>
- <item name="disableChildrenWhenDisabled">true</item>
- </style>
-
<style name="Base.Widget.AppCompat.DropDownItem.Spinner" parent="">
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.DropDownItem</item>
<item name="android:paddingLeft">8dp</item>
@@ -320,9 +310,9 @@
</style>
<style name="Base.Widget.AppCompat.Toolbar.Button.Navigation" parent="android:Widget">
+ <item name="android:background">?attr/controlBackground</item>
<item name="android:minWidth">56dp</item>
<item name="android:scaleType">center</item>
- <item name="android:background">?attr/selectableItemBackground</item>
</style>
<style name="Base.TextAppearance.Widget.AppCompat.Toolbar.Title"
@@ -379,19 +369,19 @@
<style name="Base.Widget.AppCompat.CompoundButton.CheckBox" parent="android:Widget.CompoundButton.CheckBox">
<item name="android:button">?android:attr/listChoiceIndicatorMultiple</item>
- <item name="android:background">?attr/selectableItemBackgroundBorderless</item>
+ <item name="android:background">?attr/controlBackground</item>
</style>
<style name="Base.Widget.AppCompat.CompoundButton.RadioButton" parent="android:Widget.CompoundButton.RadioButton">
<item name="android:button">?android:attr/listChoiceIndicatorSingle</item>
- <item name="android:background">?attr/selectableItemBackgroundBorderless</item>
+ <item name="android:background">?attr/controlBackground</item>
</style>
<style name="Base.Widget.AppCompat.CompoundButton.Switch" parent="android:Widget.CompoundButton">
<item name="track">@drawable/abc_switch_track_mtrl_alpha</item>
<item name="android:thumb">@drawable/abc_switch_thumb_material</item>
<item name="switchTextAppearance">@style/TextAppearance.AppCompat.Widget.Switch</item>
- <item name="android:background">?attr/selectableItemBackgroundBorderless</item>
+ <item name="android:background">?attr/controlBackground</item>
<item name="showText">false</item>
<item name="switchPadding">@dimen/abc_switch_padding</item>
</style>
@@ -420,6 +410,12 @@
<item name="android:minWidth">48dip</item>
</style>
+ <!-- Colored bordered ink button -->
+ <style name="Base.Widget.AppCompat.Button.Colored">
+ <item name="android:background">@drawable/abc_btn_colored_material</item>
+ <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Inverse</item>
+ </style>
+
<!-- Borderless ink button -->
<style name="Base.Widget.AppCompat.Button.Borderless">
<item name="android:background">@drawable/abc_btn_borderless_material</item>
@@ -466,9 +462,7 @@
<item name="android:background">@null</item>
</style>
- <style name="Base.Widget.AppCompat.ButtonBar.AlertDialog">
- <item name="android:background">@null</item>
- </style>
+ <style name="Base.Widget.AppCompat.ButtonBar.AlertDialog" />
<style name="Base.Animation.AppCompat.DropDownUp" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/abc_grow_fade_in_from_bottom</item>
diff --git a/v7/appcompat/res/values/styles_base_text.xml b/v7/appcompat/res/values/styles_base_text.xml
index 3a2799a..8597179 100644
--- a/v7/appcompat/res/values/styles_base_text.xml
+++ b/v7/appcompat/res/values/styles_base_text.xml
@@ -96,6 +96,12 @@
<item name="android:textColor">?android:textColorPrimary</item>
</style>
+ <style name="Base.TextAppearance.AppCompat.Widget.Button" parent="TextAppearance.AppCompat.Button" />
+
+ <style name="Base.TextAppearance.AppCompat.Widget.Button.Inverse" parent="TextAppearance.AppCompat.Button">
+ <item name="android:textColor">?android:textColorPrimaryInverse</item>
+ </style>
+
<!-- Deprecated text styles -->
<style name="Base.TextAppearance.AppCompat.Inverse">
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index 3aba36e..9e9a4ab 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -26,8 +26,8 @@
<item name="android:windowNoTitle">true</item>
<!-- Window colors -->
- <item name="android:colorForeground">@color/bright_foreground_material_dark</item>
- <item name="android:colorForegroundInverse">@color/bright_foreground_material_light</item>
+ <item name="android:colorForeground">@color/foreground_material_dark</item>
+ <item name="android:colorForegroundInverse">@color/foreground_material_light</item>
<item name="android:colorBackground">@color/background_material_dark</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_dark</item>
<item name="android:disabledAlpha">@dimen/abc_disabled_alpha_material_dark</item>
@@ -65,8 +65,8 @@
<item name="android:windowNoTitle">true</item>
<!-- Window colors -->
- <item name="android:colorForeground">@color/bright_foreground_material_light</item>
- <item name="android:colorForegroundInverse">@color/bright_foreground_material_dark</item>
+ <item name="android:colorForeground">@color/foreground_material_light</item>
+ <item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
<item name="android:colorBackground">@color/background_material_light</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
<item name="android:disabledAlpha">@dimen/abc_disabled_alpha_material_light</item>
@@ -219,6 +219,7 @@
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/button_material_dark</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
+ <item name="controlBackground">?attr/selectableItemBackgroundBorderless</item>
<item name="drawerArrowStyle">@style/Widget.AppCompat.DrawerArrowToggle</item>
@@ -231,7 +232,7 @@
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.AppCompat.Button</item>
<item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
- <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Button</item>
+ <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
<item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
<item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
@@ -367,6 +368,7 @@
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/button_material_light</item>
<item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
+ <item name="controlBackground">?attr/selectableItemBackgroundBorderless</item>
<item name="drawerArrowStyle">@style/Widget.AppCompat.DrawerArrowToggle</item>
@@ -379,7 +381,7 @@
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.AppCompat.Button</item>
<item name="buttonStyleSmall">@style/Widget.AppCompat.Button.Small</item>
- <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Button</item>
+ <item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Widget.Button</item>
<item name="buttonBarStyle">@style/Widget.AppCompat.ButtonBar</item>
<item name="buttonBarButtonStyle">@style/Widget.AppCompat.Button.ButtonBar.AlertDialog</item>
@@ -546,8 +548,8 @@
<style name="Base.ThemeOverlay.AppCompat.Light" parent="Platform.ThemeOverlay.AppCompat.Light">
<item name="android:windowBackground">@color/background_material_light</item>
- <item name="android:colorForeground">@color/bright_foreground_material_light</item>
- <item name="android:colorForegroundInverse">@color/bright_foreground_material_dark</item>
+ <item name="android:colorForeground">@color/foreground_material_light</item>
+ <item name="android:colorForegroundInverse">@color/foreground_material_dark</item>
<item name="android:colorBackground">@color/background_material_light</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_light</item>
@@ -575,8 +577,8 @@
<style name="Base.ThemeOverlay.AppCompat.Dark" parent="Platform.ThemeOverlay.AppCompat.Dark">
<item name="android:windowBackground">@color/background_material_dark</item>
- <item name="android:colorForeground">@color/bright_foreground_material_dark</item>
- <item name="android:colorForegroundInverse">@color/bright_foreground_material_light</item>
+ <item name="android:colorForeground">@color/foreground_material_dark</item>
+ <item name="android:colorForegroundInverse">@color/foreground_material_light</item>
<item name="android:colorBackground">@color/background_material_dark</item>
<item name="android:colorBackgroundCacheHint">@color/abc_background_cache_hint_selector_material_dark</item>
diff --git a/v7/appcompat/res/values/themes_daynight.xml b/v7/appcompat/res/values/themes_daynight.xml
new file mode 100644
index 0000000..bc7001d
--- /dev/null
+++ b/v7/appcompat/res/values/themes_daynight.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <!-- Material theme (day/night vesion) for activities. -->
+ <style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat.Light" />
+
+ <!-- Variant of AppCompat.DayNight that has a solid (opaque) action bar
+ with an inverse color profile. The dark action bar sharply stands out against
+ the light content (when applicable). -->
+ <style name="Theme.AppCompat.DayNight.DarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar" />
+
+ <!-- Variant of AppCompat.DayNight with no action bar. -->
+ <style name="Theme.AppCompat.DayNight.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar" />
+
+ <!-- Material theme (day/night vesion) for dialog windows and activities,
+ which is used by the {@code android.support.v7.app.Dialog} class. This changes
+ the window to be floating (not fill the entire screen), and puts a
+ frame around its contents. You can set this theme on an activity if
+ you would like to make an activity that looks like a Dialog. -->
+ <style name="Theme.AppCompat.DayNight.Dialog" parent="Theme.AppCompat.Light.Dialog" />
+
+ <!-- Variant of Theme.AppCompat.DayNight.Dialog that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.AppCompat.DayNight.Dialog.MinWidth" parent="Theme.AppCompat.Light.Dialog.MinWidth" />
+
+ <!-- Theme for a window that will be displayed either full-screen on
+ smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.AppCompat.DayNight.DialogWhenLarge" parent="Theme.AppCompat.Light.DialogWhenLarge" />
+
+ <!-- Material user theme for alert dialog windows, which is used by the
+ {@code android.support.v7.app.AlertDialog} class. -->
+ <style name="Theme.AppCompat.DayNight.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog.Alert" />
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/app/ActionBar.java b/v7/appcompat/src/android/support/v7/app/ActionBar.java
index d48dd31..2564031 100644
--- a/v7/appcompat/src/android/support/v7/app/ActionBar.java
+++ b/v7/appcompat/src/android/support/v7/app/ActionBar.java
@@ -46,45 +46,38 @@
* A primary toolbar within the activity that may display the activity title, application-level
* navigation affordances, and other interactive items.
*
- * <p>Beginning with Android 3.0 (API level 11), the action bar appears at the top of an
- * activity's window when the activity uses the system's {@link
- * android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default.
+ * <p>The action bar appears at the top of an activity's window when the activity uses the
+ * AppCompat's {@link R.style#Theme_AppCompat AppCompat} theme (or one of its descendant themes).
* You may otherwise add the action bar by calling {@link
- * android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a
- * custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property.
+ * AppCompatDelegate#requestWindowFeature(int) requestFeature(FEATURE_SUPPORT_ACTION_BAR)} or by
+ * declaring it in a custom theme with the {@link R.styleable#Theme_windowActionBar windowActionBar}
+ * property.
* </p>
*
- * <p>Beginning with Android L (API level 21), the action bar may be represented by any
- * Toolbar widget within the application layout. The application may signal to the Activity
- * which Toolbar should be treated as the Activity's action bar. Activities that use this
- * feature should use one of the supplied <code>.NoActionBar</code> themes, set the
- * {@link android.R.styleable#Theme_windowActionBar windowActionBar} attribute to <code>false</code>
+ * <p>The action bar may be represented by any Toolbar widget within the application layout.
+ * The application may signal to the Activity which Toolbar should be treated as the Activity's
+ * action bar. Activities that use this feature should use one of the supplied
+ * <code>.NoActionBar</code> themes, set the
+ * {@link R.styleable#Theme_windowActionBar windowActionBar} attribute to <code>false</code>
* or otherwise not request the window feature.</p>
*
- * <p>By adjusting the window features requested by the theme and the layouts used for
- * an Activity's content view, an app can use the standard system action bar on older platform
- * releases and the newer inline toolbars on newer platform releases. The <code>ActionBar</code>
- * object obtained from the Activity can be used to control either configuration transparently.</p>
+ * <p>If your activity has an options menu, you can make select items accessible directly from the
+ * action bar as "action items". You can also modify various characteristics of the action bar or
+ * remove it completely.</p>
*
- * <p>When using the Holo themes the action bar shows the application icon on
- * the left, followed by the activity title. If your activity has an options menu, you can make
- * select items accessible directly from the action bar as "action items". You can also
- * modify various characteristics of the action bar or remove it completely.</p>
- *
- * <p>When using the Material themes (default in API 21 or newer) the navigation button
- * (formerly "Home") takes over the space previously occupied by the application icon.
- * Apps wishing to express a stronger branding should use their brand colors heavily
- * in the action bar and other application chrome or use a {@link #setLogo(int) logo}
+ * <p>The navigation button (formerly "Home") takes over the space previously occupied by the
+ * application icon. Apps wishing to express a stronger branding should use their brand colors
+ * heavily in the action bar and other application chrome or use a {@link #setLogo(int) logo}
* in place of their standard title text.</p>
*
* <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
- * android.app.Activity#getActionBar getActionBar()}.</p>
+ * AppCompatActivity#getSupportActionBar()} getSupportActionBar()}.</p>
*
* <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,
- * using an {@link android.view.ActionMode}. For example, when the user selects one or more items in
+ * using an {@link ActionMode}. For example, when the user selects one or more items in
* your activity, you can enable an action mode that offers actions specific to the selected
* items, with a UI that temporarily replaces the action bar. Although the UI may occupy the
- * same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for
+ * same space, the {@link ActionMode} APIs are distinct and independent from those for
* {@link ActionBar}.</p>
*
* <div class="special reference">
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
index e4283e3..2ce12ce 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatActivity.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.support.annotation.CallSuper;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
@@ -27,6 +28,7 @@
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.Toolbar;
+import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -60,6 +62,12 @@
}
@Override
+ public void setTheme(int resid) {
+ getDelegate().applyDayNight();
+ super.setTheme(resid);
+ }
+
+ @Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
@@ -88,7 +96,8 @@
* {@link android.R.id#home home} menu select action.</p>
*
* <p>In order to use a Toolbar within the Activity's window content the application
- * must not request the window feature {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p>
+ * must not request the window feature
+ * {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
*
* @param toolbar Toolbar to set as the Activity's action bar
*/
@@ -201,6 +210,7 @@
*
* @param mode The new action mode.
*/
+ @CallSuper
public void onSupportActionModeStarted(ActionMode mode) {
}
@@ -210,6 +220,7 @@
*
* @param mode The action mode that just finished.
*/
+ @CallSuper
public void onSupportActionModeFinished(ActionMode mode) {
}
@@ -422,6 +433,28 @@
}
/**
+ * {@inheritDoc}
+ *
+ * <p>Please note: AppCompat uses it's own feature id for the action bar:
+ * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
+ */
+ @Override
+ public boolean onMenuOpened(int featureId, Menu menu) {
+ return super.onMenuOpened(featureId, menu);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Please note: AppCompat uses it's own feature id for the action bar:
+ * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
+ */
+ @Override
+ public void onPanelClosed(int featureId, Menu menu) {
+ super.onPanelClosed(featureId, menu);
+ }
+
+ /**
* @return The {@link AppCompatDelegate} being used by this Activity.
*/
public AppCompatDelegate getDelegate() {
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
index 3abe072..d04e89e 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegate.java
@@ -22,8 +22,12 @@
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.IntDef;
+import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
+import android.support.v4.view.WindowCompat;
+import android.support.v7.appcompat.R;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
@@ -32,6 +36,9 @@
import android.view.ViewGroup;
import android.view.Window;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class represents a delegate which you can use to extend AppCompat's support to any
* {@link android.app.Activity}.
@@ -69,6 +76,73 @@
static final String TAG = "AppCompatDelegate";
/**
+ * Mode which means to not use night mode, and therefore not use {@code night} qualified
+ * resources, regardless of the time.
+ *
+ * @see #setNightMode(int)
+ */
+ public static final int MODE_NIGHT_NO = 0;
+
+ /**
+ * Mode which means to always use night mode, and therefore use {@code night} qualified
+ * resources, regardless of the time.
+ *
+ * @see #setNightMode(int)
+ */
+ public static final int MODE_NIGHT_YES = 1;
+
+ /**
+ * Mode which means to use night mode when it is determined that it is night or not..
+ *
+ * <p>The calculation used to determine whether it is night or not makes use of the location
+ * APIs (if this app has the necessary permissions). This allows us to generate accurate
+ * sunrise and sunset times. If this app does not have permission to access the location APIs
+ * then we use hardcoded times which will be less accurate.</p>
+ *
+ * <p>This is the default mode.</p>
+ *
+ * @see #setNightMode(int)
+ */
+ public static final int MODE_NIGHT_AUTO = 2;
+
+ @IntDef({MODE_NIGHT_NO, MODE_NIGHT_YES, MODE_NIGHT_AUTO})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface NightMode {}
+
+ /**
+ * Flag for enabling the support Action Bar.
+ *
+ * <p>This is enabled by default for some devices. The Action Bar replaces the title bar and
+ * provides an alternate location for an on-screen menu button on some devices.
+ */
+ public static final int FEATURE_SUPPORT_ACTION_BAR = 100 + WindowCompat.FEATURE_ACTION_BAR;
+
+ /**
+ * Flag for requesting an support Action Bar that overlays window content.
+ * Normally an Action Bar will sit in the space above window content, but if this
+ * feature is requested along with {@link #FEATURE_SUPPORT_ACTION_BAR} it will be layered over
+ * the window content itself. This is useful if you would like your app to have more control
+ * over how the Action Bar is displayed, such as letting application content scroll beneath
+ * an Action Bar with a transparent background or otherwise displaying a transparent/translucent
+ * Action Bar over application content.
+ *
+ * <p>This mode is especially useful with {@code View.SYSTEM_UI_FLAG_FULLSCREEN}, which allows
+ * you to seamlessly hide the action bar in conjunction with other screen decorations.
+ * When an ActionBar is in this mode it will adjust the insets provided to
+ * {@link View#fitSystemWindows(android.graphics.Rect) View.fitSystemWindows(Rect)}
+ * to include the content covered by the action bar, so you can do layout within
+ * that space.
+ */
+ public static final int FEATURE_SUPPORT_ACTION_BAR_OVERLAY =
+ 100 + WindowCompat.FEATURE_ACTION_BAR_OVERLAY;
+
+ /**
+ * Flag for specifying the behavior of action modes when an Action Bar is not present.
+ * If overlay is enabled, the action mode UI will be allowed to cover existing window content.
+ */
+ public static final int FEATURE_ACTION_MODE_OVERLAY = WindowCompat.FEATURE_ACTION_MODE_OVERLAY;
+
+ /**
* Create a {@link android.support.v7.app.AppCompatDelegate} to use with {@code activity}.
*
* @param callback An optional callback for AppCompat specific events
@@ -89,7 +163,9 @@
private static AppCompatDelegate create(Context context, Window window,
AppCompatCallback callback) {
final int sdk = Build.VERSION.SDK_INT;
- if (sdk >= 14) {
+ if (sdk >= 23) {
+ return new AppCompatDelegateImplV23(context, window, callback);
+ } else if (sdk >= 14) {
return new AppCompatDelegateImplV14(context, window, callback);
} else if (sdk >= 11) {
return new AppCompatDelegateImplV11(context, window, callback);
@@ -121,7 +197,7 @@
*
* <p>In order to use a Toolbar within the Activity's window content the application
* must not request the window feature
- * {@link android.view.Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p>
+ * {@link AppCompatDelegate#FEATURE_SUPPORT_ACTION_BAR FEATURE_SUPPORT_ACTION_BAR}.</p>
*
* @param toolbar Toolbar to set as the Activity's action bar
*/
@@ -166,7 +242,7 @@
/**
* Should be called instead of {@link Activity#setContentView(int)}}
*/
- public abstract void setContentView(int resId);
+ public abstract void setContentView(@LayoutRes int resId);
/**
* Should be called instead of
@@ -279,4 +355,31 @@
*/
public abstract boolean isHandleNativeActionModesEnabled();
+ /**
+ * Allow AppCompat to apply the {@code night} and {@code notnight} resource qualifiers.
+ *
+ * <p>Doing this enables the
+ * {@link R.style#Theme_AppCompat_DayNight Theme.AppCompat.DayNight}
+ * family of themes to work, using the computed twilight to automatically select a dark or
+ * light theme.</p>
+ *
+ * <p>You can override the night mode using {@link #setNightMode(int)}.</p>
+ *
+ * <p>This only works on devices running
+ * {@link Build.VERSION_CODES#ICE_CREAM_SANDWICH ICE_CREAM_SANDWICH} and above.</p>
+ *
+ * @see #setNightMode(int)
+ */
+ public abstract void applyDayNight();
+
+ /**
+ * Override the night mode used when {@link #applyDayNight()} is called. This method only takes
+ * effect for those situtations where {@link #applyDayNight()} works.
+ *
+ * <p>This needs to be called before {@link #applyDayNight()}. Defaults to
+ * {@link #MODE_NIGHT_AUTO}.</p>
+ *
+ * @see #applyDayNight()
+ */
+ public abstract void setNightMode(@NightMode int mode);
}
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
index 316256c..1c5f98e 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplBase.java
@@ -21,7 +21,6 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.support.v4.view.WindowCompat;
import android.support.v7.appcompat.R;
import android.support.v7.internal.view.SupportMenuInflater;
import android.support.v7.internal.view.WindowCallbackWrapper;
@@ -118,20 +117,20 @@
requestWindowFeature(Window.FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Theme_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
- requestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
+ requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR);
}
if (a.getBoolean(R.styleable.Theme_windowActionBarOverlay, false)) {
- requestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY);
+ requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
}
if (a.getBoolean(R.styleable.Theme_windowActionModeOverlay, false)) {
- requestWindowFeature(WindowCompat.FEATURE_ACTION_MODE_OVERLAY);
+ requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY);
}
mIsFloating = a.getBoolean(R.styleable.Theme_android_windowIsFloating, false);
a.recycle();
}
// Methods used to create and respond to options menu
- abstract boolean onPanelClosed(int featureId, Menu menu);
+ abstract void onPanelClosed(int featureId, Menu menu);
abstract boolean onMenuOpened(int featureId, Menu menu);
@@ -140,6 +139,11 @@
abstract boolean onKeyShortcut(int keyCode, KeyEvent event);
@Override
+ public void setNightMode(@NightMode int mode) {
+ // no-op
+ }
+
+ @Override
public final ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() {
return new ActionBarDrawableToggleImpl();
}
@@ -216,6 +220,11 @@
return false;
}
+ @Override
+ public void applyDayNight() {
+ // no-op on v7
+ }
+
final boolean isDestroyed() {
return mIsDestroyed;
}
@@ -248,12 +257,14 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- if (AppCompatDelegateImplBase.this.dispatchKeyEvent(event)) {
- // First, let us attempt to handle it
- return true;
- }
- // If we reach here, let the wrapped Callback attempt to handle it
- return super.dispatchKeyEvent(event);
+ return AppCompatDelegateImplBase.this.dispatchKeyEvent(event)
+ || super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ return super.dispatchKeyShortcutEvent(event)
+ || AppCompatDelegateImplBase.this.onKeyShortcut(event.getKeyCode(), event);
}
@Override
@@ -267,6 +278,12 @@
}
@Override
+ public void onContentChanged() {
+ // We purposely do not propagate this call as this is called when we install
+ // our sub-decor rather than the user's content
+ }
+
+ @Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
@@ -295,32 +312,14 @@
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
- if (AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu)) {
- return true;
- }
- return super.onMenuOpened(featureId, menu);
- }
-
- @Override
- public boolean dispatchKeyShortcutEvent(KeyEvent event) {
- if (AppCompatDelegateImplBase.this.onKeyShortcut(event.getKeyCode(), event)) {
- return true;
- }
- return super.dispatchKeyShortcutEvent(event);
- }
-
- @Override
- public void onContentChanged() {
- // We purposely do not propagate this call as this is called when we install
- // our sub-decor rather than the user's content
+ return super.onMenuOpened(featureId, menu)
+ || AppCompatDelegateImplBase.this.onMenuOpened(featureId, menu);
}
@Override
public void onPanelClosed(int featureId, Menu menu) {
- if (AppCompatDelegateImplBase.this.onPanelClosed(featureId, menu)) {
- return;
- }
super.onPanelClosed(featureId, menu);
+ AppCompatDelegateImplBase.this.onPanelClosed(featureId, menu);
}
}
}
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
index 5ab3a10..d6b0ea1 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV14.java
@@ -16,15 +16,23 @@
package android.support.v7.app;
+import android.app.UiModeManager;
import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Build;
import android.support.v7.internal.view.SupportActionModeWrapper;
import android.view.ActionMode;
import android.view.Window;
class AppCompatDelegateImplV14 extends AppCompatDelegateImplV11 {
+ private TwilightManager mTwilightManager;
private boolean mHandleNativeActionModes = true; // defaults to true
+ @NightMode
+ private int mNightMode = MODE_NIGHT_AUTO;
+
AppCompatDelegateImplV14(Context context, Window window, AppCompatCallback callback) {
super(context, window, callback);
}
@@ -46,6 +54,90 @@
return mHandleNativeActionModes;
}
+ @Override
+ public void applyDayNight() {
+ if (!isSystemControllingNightMode()) {
+ // If the system is not controlling night mode, let's do it ourselves
+ switch (mNightMode) {
+ case MODE_NIGHT_AUTO:
+ // For auto, we need to check whether it's night or not
+ setDayNightUsingTwilight();
+ break;
+ default:
+ // Else, we'll set the value directly
+ setDayNightConfiguration(mNightMode);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void setNightMode(@NightMode int mode) {
+ mNightMode = mode;
+ }
+
+ /**
+ * If possible, updates the Activity's {@link uiMode} to match whether we are at night or not.
+ */
+ void setDayNightUsingTwilight() {
+ // If the system isn't controlling night mode, we'll do it ourselves
+ if (getTwilightManager().isNight()) {
+ // If we're at 'night', set the night mode
+ setDayNightConfiguration(MODE_NIGHT_YES);
+ } else {
+ // Else, set the day mode
+ setDayNightConfiguration(MODE_NIGHT_NO);
+ }
+ }
+
+ /**
+ * Updates the {@link Resources} configuration {@code uiMode} with the
+ * chosen {@code UI_MODE_NIGHT} value.
+ */
+ void setDayNightConfiguration(@NightMode int mode) {
+ final Resources res = mContext.getResources();
+ final Configuration conf = res.getConfiguration();
+ final int currentNightMode = conf.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+
+ int newNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
+ switch (mode) {
+ case MODE_NIGHT_NO:
+ newNightMode = Configuration.UI_MODE_NIGHT_NO;
+ break;
+ case MODE_NIGHT_YES:
+ newNightMode = Configuration.UI_MODE_NIGHT_YES;
+ break;
+ }
+
+ if (currentNightMode != newNightMode) {
+ conf.uiMode = (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | newNightMode;
+ res.updateConfiguration(conf, res.getDisplayMetrics());
+ }
+ }
+
+ /**
+ * Returns true if the system is controlling night mode.
+ */
+ private boolean isSystemControllingNightMode() {
+ final UiModeManager uiModeManager =
+ (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
+
+ if (Build.VERSION.SDK_INT < 23
+ && uiModeManager.getCurrentModeType() != Configuration.UI_MODE_TYPE_CAR) {
+ // Night mode only has an effect with car mode enabled on < API v23
+ return false;
+ }
+
+ return uiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO;
+ }
+
+ private TwilightManager getTwilightManager() {
+ if (mTwilightManager == null) {
+ mTwilightManager = new TwilightManager(mContext);
+ }
+ return mTwilightManager;
+ }
+
class AppCompatWindowCallbackV14 extends AppCompatWindowCallbackBase {
AppCompatWindowCallbackV14(Window.Callback callback) {
super(callback);
@@ -54,7 +146,7 @@
@Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
// We wrap in a support action mode on v14+ if enabled
- if (mHandleNativeActionModes) {
+ if (isHandleNativeActionModesEnabled()) {
return startAsSupportActionMode(callback);
}
// Else, let the call fall through to the wrapped callback
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java
new file mode 100644
index 0000000..7b4c5ae
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV23.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.app;
+
+import android.content.Context;
+import android.view.ActionMode;
+import android.view.Window;
+
+class AppCompatDelegateImplV23 extends AppCompatDelegateImplV14 {
+
+ AppCompatDelegateImplV23(Context context, Window window, AppCompatCallback callback) {
+ super(context, window, callback);
+ }
+
+ @Override
+ Window.Callback wrapWindowCallback(Window.Callback callback) {
+ // Override the window callback so that we can intercept onWindowStartingActionMode(type)
+ // calls
+ return new AppCompatWindowCallbackV23(callback);
+ }
+
+ class AppCompatWindowCallbackV23 extends AppCompatWindowCallbackV14 {
+ AppCompatWindowCallbackV23(Window.Callback callback) {
+ super(callback);
+ }
+
+ @Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
+ if (isHandleNativeActionModesEnabled()) {
+ switch (type) {
+ case ActionMode.TYPE_PRIMARY:
+ // We only take over if the type is TYPE_PRIMARY
+ return startAsSupportActionMode(callback);
+ }
+ }
+ // Else, let the call fall through to the wrapped callback
+ return super.onWindowStartingActionMode(callback, type);
+ }
+
+ @Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
+ // No-op on API 23+
+ return null;
+ }
+ }
+
+ @Override
+ public void applyDayNight() {
+ // no-op. Let the framework handle DayNight stuff
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
index f545bda..cea89c7 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
@@ -36,7 +36,11 @@
import android.support.v4.view.OnApplyWindowInsetsListener;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewConfigurationCompat;
+import android.support.v4.view.ViewPropertyAnimatorCompat;
+import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
+import android.support.v4.view.WindowCompat;
import android.support.v4.view.WindowInsetsCompat;
+import android.support.v4.widget.PopupWindowCompat;
import android.support.v7.appcompat.R;
import android.support.v7.internal.app.AppCompatViewInflater;
import android.support.v7.internal.app.ToolbarActionBar;
@@ -79,9 +83,6 @@
import android.widget.PopupWindow;
import android.widget.TextView;
-import static android.support.v4.view.WindowCompat.FEATURE_ACTION_BAR;
-import static android.support.v4.view.WindowCompat.FEATURE_ACTION_BAR_OVERLAY;
-import static android.support.v4.view.WindowCompat.FEATURE_ACTION_MODE_OVERLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.Window.FEATURE_OPTIONS_PANEL;
@@ -97,6 +98,7 @@
ActionBarContextView mActionModeView;
PopupWindow mActionModePopup;
Runnable mShowActionModePopup;
+ ViewPropertyAnimatorCompat mFadeAnim = null;
// true if we have installed a window sub-decor layout.
private boolean mSubDecorInstalled;
@@ -122,8 +124,8 @@
if ((mInvalidatePanelMenuFeatures & 1 << FEATURE_OPTIONS_PANEL) != 0) {
doInvalidatePanelMenu(FEATURE_OPTIONS_PANEL);
}
- if ((mInvalidatePanelMenuFeatures & 1 << FEATURE_ACTION_BAR) != 0) {
- doInvalidatePanelMenu(FEATURE_ACTION_BAR);
+ if ((mInvalidatePanelMenuFeatures & 1 << FEATURE_SUPPORT_ACTION_BAR) != 0) {
+ doInvalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
}
mInvalidatePanelMenuPosted = false;
mInvalidatePanelMenuFeatures = 0;
@@ -195,7 +197,7 @@
final ActionBar ab = getSupportActionBar();
if (ab instanceof WindowDecorActionBar) {
throw new IllegalStateException("This Activity already has an action bar supplied " +
- "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
+ "by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set " +
"windowActionBar to false in your theme to use a Toolbar instead.");
}
// Clear out the MenuInflater to make sure that it is valid for the new Action Bar
@@ -313,7 +315,7 @@
* Propagate features to DecorContentParent
*/
if (mOverlayActionBar) {
- mDecorContentParent.initFeature(FEATURE_ACTION_BAR_OVERLAY);
+ mDecorContentParent.initFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
}
if (mFeatureProgress) {
mDecorContentParent.initFeature(Window.FEATURE_PROGRESS);
@@ -428,7 +430,7 @@
// would run normally in order to satisfy instance state restoration.
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!isDestroyed() && (st == null || st.menu == null)) {
- invalidatePanelMenu(FEATURE_ACTION_BAR);
+ invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
}
}
}
@@ -472,7 +474,9 @@
@Override
public boolean requestWindowFeature(int featureId) {
- if (mWindowNoTitle && featureId == FEATURE_ACTION_BAR) {
+ featureId = sanitizeWindowFeatureId(featureId);
+
+ if (mWindowNoTitle && featureId == FEATURE_SUPPORT_ACTION_BAR) {
return false; // Ignore. No title dominates.
}
if (mHasActionBar && featureId == Window.FEATURE_NO_TITLE) {
@@ -481,11 +485,11 @@
}
switch (featureId) {
- case FEATURE_ACTION_BAR:
+ case FEATURE_SUPPORT_ACTION_BAR:
throwFeatureRequestIfSubDecorInstalled();
mHasActionBar = true;
return true;
- case FEATURE_ACTION_BAR_OVERLAY:
+ case FEATURE_SUPPORT_ACTION_BAR_OVERLAY:
throwFeatureRequestIfSubDecorInstalled();
mOverlayActionBar = true;
return true;
@@ -512,10 +516,11 @@
@Override
public boolean hasWindowFeature(int featureId) {
+ featureId = sanitizeWindowFeatureId(featureId);
switch (featureId) {
- case FEATURE_ACTION_BAR:
+ case FEATURE_SUPPORT_ACTION_BAR:
return mHasActionBar;
- case FEATURE_ACTION_BAR_OVERLAY:
+ case FEATURE_SUPPORT_ACTION_BAR_OVERLAY:
return mOverlayActionBar;
case FEATURE_ACTION_MODE_OVERLAY:
return mOverlayActionMode;
@@ -541,13 +546,12 @@
}
@Override
- boolean onPanelClosed(final int featureId, Menu menu) {
- if (featureId == FEATURE_ACTION_BAR) {
+ void onPanelClosed(final int featureId, Menu menu) {
+ if (featureId == FEATURE_SUPPORT_ACTION_BAR) {
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.dispatchMenuVisibilityChanged(false);
}
- return true;
} else if (featureId == FEATURE_OPTIONS_PANEL) {
// Make sure that the options panel is closed. This is mainly used when we're using a
// ToolbarActionBar
@@ -556,12 +560,11 @@
closePanel(st, false);
}
}
- return false;
}
@Override
boolean onMenuOpened(final int featureId, Menu menu) {
- if (featureId == FEATURE_ACTION_BAR) {
+ if (featureId == FEATURE_SUPPORT_ACTION_BAR) {
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.dispatchMenuVisibilityChanged(true);
@@ -626,6 +629,7 @@
@Override
ActionMode startSupportActionModeFromWindow(ActionMode.Callback callback) {
+ endOnGoingFadeAnimation();
if (mActionMode != null) {
mActionMode.finish();
}
@@ -665,6 +669,8 @@
mActionModeView = new ActionBarContextView(actionBarContext);
mActionModePopup = new PopupWindow(actionBarContext, null,
R.attr.actionModePopupWindowStyle);
+ PopupWindowCompat.setWindowLayoutType(mActionModePopup,
+ WindowManager.LayoutParams.TYPE_APPLICATION);
mActionModePopup.setContentView(mActionModeView);
mActionModePopup.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
@@ -679,6 +685,22 @@
mActionModePopup.showAtLocation(
mActionModeView,
Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
+ endOnGoingFadeAnimation();
+ ViewCompat.setAlpha(mActionModeView, 0f);
+ mFadeAnim = ViewCompat.animate(mActionModeView).alpha(1f);
+ mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(View view) {
+ ViewCompat.setAlpha(mActionModeView, 1f);
+ mFadeAnim.setListener(null);
+ mFadeAnim = null;
+ }
+
+ @Override
+ public void onAnimationStart(View view) {
+ mActionModeView.setVisibility(View.VISIBLE);
+ }
+ });
}
};
} else {
@@ -693,14 +715,29 @@
}
if (mActionModeView != null) {
+ endOnGoingFadeAnimation();
mActionModeView.killMode();
mode = new StandaloneActionMode(mActionModeView.getContext(), mActionModeView,
wrappedCallback, mActionModePopup == null);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mode.invalidate();
mActionModeView.initForMode(mode);
- mActionModeView.setVisibility(View.VISIBLE);
mActionMode = mode;
+ ViewCompat.setAlpha(mActionModeView, 0f);
+ mFadeAnim = ViewCompat.animate(mActionModeView).alpha(1f);
+ mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(View view) {
+ ViewCompat.setAlpha(mActionModeView, 1f);
+ mFadeAnim.setListener(null);
+ mFadeAnim = null;
+ }
+
+ @Override
+ public void onAnimationStart(View view) {
+ mActionModeView.setVisibility(View.VISIBLE);
+ }
+ });
if (mActionModePopup != null) {
mWindow.getDecorView().post(mShowActionModePopup);
}
@@ -721,6 +758,12 @@
return mActionMode;
}
+ private void endOnGoingFadeAnimation() {
+ if (mFadeAnim != null) {
+ mFadeAnim.cancel();
+ }
+ }
+
boolean onBackPressed() {
// Back cancels action modes first.
if (mActionMode != null) {
@@ -1016,7 +1059,7 @@
// forget it. This is a lingering event that no longer matters.
if (st.menu != null && !st.refreshMenuContent &&
cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
- cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
+ cb.onMenuOpened(FEATURE_SUPPORT_ACTION_BAR, st.menu);
mDecorContentParent.showOverflowMenu();
}
}
@@ -1024,7 +1067,7 @@
mDecorContentParent.hideOverflowMenu();
if (!isDestroyed()) {
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
- cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
+ cb.onPanelClosed(FEATURE_SUPPORT_ACTION_BAR, st.menu);
}
}
return;
@@ -1042,7 +1085,7 @@
Context context = mContext;
// If we have an action bar, initialize the menu with the right theme.
- if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
+ if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_SUPPORT_ACTION_BAR) &&
mDecorContentParent != null) {
final TypedValue outValue = new TypedValue();
final Resources.Theme baseTheme = context.getTheme();
@@ -1124,7 +1167,7 @@
}
final boolean isActionBarMenu =
- (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
+ (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_SUPPORT_ACTION_BAR);
if (isActionBarMenu && mDecorContentParent != null) {
// Enforce ordering guarantees around events so that the action bar never
@@ -1215,7 +1258,7 @@
mDecorContentParent.dismissPopups();
Window.Callback cb = getWindowCallback();
if (cb != null && !isDestroyed()) {
- cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
+ cb.onPanelClosed(FEATURE_SUPPORT_ACTION_BAR, menu);
}
mClosingActionMenu = false;
}
@@ -1430,7 +1473,7 @@
st.refreshDecorView = true;
// Prepare the options panel if we have an action bar
- if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
+ if ((featureId == FEATURE_SUPPORT_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
&& mDecorContentParent != null) {
st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
if (st != null) {
@@ -1523,6 +1566,20 @@
}
}
+ private int sanitizeWindowFeatureId(int featureId) {
+ if (featureId == WindowCompat.FEATURE_ACTION_BAR) {
+ Log.i(TAG, "You should now use the AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR"
+ + " id when requesting this feature.");
+ return FEATURE_SUPPORT_ACTION_BAR;
+ } else if (featureId == WindowCompat.FEATURE_ACTION_BAR_OVERLAY) {
+ Log.i(TAG, "You should now use the AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR_OVERLAY"
+ + " id when requesting this feature.");
+ return FEATURE_SUPPORT_ACTION_BAR_OVERLAY;
+ }
+ // Else we'll just return the original id
+ return featureId;
+ }
+
ViewGroup getSubDecor() {
return mSubDecor;
}
@@ -1553,15 +1610,25 @@
mWrapped.onDestroyActionMode(mode);
if (mActionModePopup != null) {
mWindow.getDecorView().removeCallbacks(mShowActionModePopup);
- mActionModePopup.dismiss();
- } else if (mActionModeView != null) {
- mActionModeView.setVisibility(View.GONE);
- if (mActionModeView.getParent() != null) {
- ViewCompat.requestApplyInsets((View) mActionModeView.getParent());
- }
}
+
if (mActionModeView != null) {
- mActionModeView.removeAllViews();
+ endOnGoingFadeAnimation();
+ mFadeAnim = ViewCompat.animate(mActionModeView).alpha(0f);
+ mFadeAnim.setListener(new ViewPropertyAnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(View view) {
+ mActionModeView.setVisibility(View.GONE);
+ if (mActionModePopup != null) {
+ mActionModePopup.dismiss();
+ } else if (mActionModeView.getParent() instanceof View) {
+ ViewCompat.requestApplyInsets((View) mActionModeView.getParent());
+ }
+ mActionModeView.removeAllViews();
+ mFadeAnim.setListener(null);
+ mFadeAnim = null;
+ }
+ });
}
if (mAppCompatCallback != null) {
mAppCompatCallback.onSupportActionModeFinished(mActionMode);
@@ -1593,7 +1660,7 @@
if (subMenu == null && mHasActionBar) {
Window.Callback cb = getWindowCallback();
if (cb != null && !isDestroyed()) {
- cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+ cb.onMenuOpened(FEATURE_SUPPORT_ACTION_BAR, subMenu);
}
}
return true;
@@ -1605,7 +1672,7 @@
public boolean onOpenSubMenu(MenuBuilder subMenu) {
Window.Callback cb = getWindowCallback();
if (cb != null) {
- cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+ cb.onMenuOpened(FEATURE_SUPPORT_ACTION_BAR, subMenu);
}
return true;
}
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java b/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
index 11688e6..5f13992 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDialog.java
@@ -46,6 +46,9 @@
// To workaround this, we call onCreate(null) in the ctor, and then again as usual in
// onCreate().
getDelegate().onCreate(null);
+
+ // Apply AppCompat's DayNight resources if needed
+ getDelegate().applyDayNight();
}
protected AppCompatDialog(Context context, boolean cancelable,
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDialogFragment.java b/v7/appcompat/src/android/support/v7/app/AppCompatDialogFragment.java
new file mode 100644
index 0000000..3051e49
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDialogFragment.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.app;
+
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.Window;
+import android.view.WindowManager;
+
+/**
+ * A special version of {@link DialogFragment} which uses an {@link AppCompatDialog} in place of a
+ * platform-styled dialog.
+ *
+ * @see DialogFragment
+ */
+public class AppCompatDialogFragment extends DialogFragment {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AppCompatDialog(getActivity(), getTheme());
+ }
+
+ /** @hide */
+ @Override
+ public void setupDialog(Dialog dialog, int style) {
+ if (dialog instanceof AppCompatDialog) {
+ // If the dialog is an AppCompatDialog, we'll handle it
+ AppCompatDialog acd = (AppCompatDialog) dialog;
+ switch (style) {
+ case STYLE_NO_INPUT:
+ dialog.getWindow().addFlags(
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
+ // fall through...
+ case STYLE_NO_FRAME:
+ case STYLE_NO_TITLE:
+ acd.supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
+ }
+ } else {
+ // Else, just let super handle it
+ super.setupDialog(dialog, style);
+ }
+ }
+
+}
diff --git a/v7/appcompat/src/android/support/v7/app/TwilightCalculator.java b/v7/appcompat/src/android/support/v7/app/TwilightCalculator.java
new file mode 100644
index 0000000..6015e12
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/TwilightCalculator.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.app;
+
+import android.text.format.DateUtils;
+
+/**
+ * Imported from frameworks/base/services/core/java/com/android/server/TwilightCalculator.java
+ *
+ * <p>Calculates the sunrise and sunsets times for a given location.</p>
+ */
+class TwilightCalculator {
+
+ private static TwilightCalculator sInstance;
+
+ static TwilightCalculator getInstance() {
+ if (sInstance == null) {
+ sInstance = new TwilightCalculator();
+ }
+ return sInstance;
+ }
+
+ /** Value of {@link #state} if it is currently day */
+ public static final int DAY = 0;
+
+ /** Value of {@link #state} if it is currently night */
+ public static final int NIGHT = 1;
+
+ private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f);
+
+ // element for calculating solar transit.
+ private static final float J0 = 0.0009f;
+
+ // correction for civil twilight
+ private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f;
+
+ // coefficients for calculating Equation of Center.
+ private static final float C1 = 0.0334196f;
+ private static final float C2 = 0.000349066f;
+ private static final float C3 = 0.000005236f;
+
+ private static final float OBLIQUITY = 0.40927971f;
+
+ // Java time on Jan 1, 2000 12:00 UTC.
+ private static final long UTC_2000 = 946728000000L;
+
+ /**
+ * Time of sunset (civil twilight) in milliseconds or -1 in the case the day
+ * or night never ends.
+ */
+ public long sunset;
+
+ /**
+ * Time of sunrise (civil twilight) in milliseconds or -1 in the case the
+ * day or night never ends.
+ */
+ public long sunrise;
+
+ /**
+ * Current state
+ */
+ public int state;
+
+ /**
+ * calculates the civil twilight bases on time and geo-coordinates.
+ *
+ * @param time time in milliseconds.
+ * @param latiude latitude in degrees.
+ * @param longitude latitude in degrees.
+ */
+ public void calculateTwilight(long time, double latiude, double longitude) {
+ final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS;
+
+ // mean anomaly
+ final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f;
+
+ // true anomaly
+ final double trueAnomaly = meanAnomaly + C1 * Math.sin(meanAnomaly) + C2
+ * Math.sin(2 * meanAnomaly) + C3 * Math.sin(3 * meanAnomaly);
+
+ // ecliptic longitude
+ final double solarLng = trueAnomaly + 1.796593063d + Math.PI;
+
+ // solar transit in days since 2000
+ final double arcLongitude = -longitude / 360;
+ float n = Math.round(daysSince2000 - J0 - arcLongitude);
+ double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053d * Math.sin(meanAnomaly)
+ + -0.0069d * Math.sin(2 * solarLng);
+
+ // declination of sun
+ double solarDec = Math.asin(Math.sin(solarLng) * Math.sin(OBLIQUITY));
+
+ final double latRad = latiude * DEGREES_TO_RADIANS;
+
+ double cosHourAngle = (Math.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
+ * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
+ // The day or night never ends for the given date and location, if this value is out of
+ // range.
+ if (cosHourAngle >= 1) {
+ state = NIGHT;
+ sunset = -1;
+ sunrise = -1;
+ return;
+ } else if (cosHourAngle <= -1) {
+ state = DAY;
+ sunset = -1;
+ sunrise = -1;
+ return;
+ }
+
+ float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI));
+
+ sunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
+ sunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
+
+ if (sunrise < time && sunset > time) {
+ state = DAY;
+ } else {
+ state = NIGHT;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/app/TwilightManager.java b/v7/appcompat/src/android/support/v7/app/TwilightManager.java
new file mode 100644
index 0000000..b17d578
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/app/TwilightManager.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.app;
+
+import android.Manifest;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationManager;
+import android.support.annotation.NonNull;
+import android.support.v4.content.PermissionChecker;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.util.Calendar;
+
+/**
+ * Class which managing whether we are in the night or not.
+ */
+class TwilightManager {
+
+ private static final String TAG = "TwilightManager";
+
+ private static final int SUNRISE = 6; // 6am
+ private static final int SUNSET = 22; // 10pm
+
+ private static final TwilightState sTwilightState = new TwilightState();
+
+ private final Context mContext;
+ private final LocationManager mLocationManager;
+
+ TwilightManager(Context context) {
+ mContext = context;
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ /**
+ * Returns true we are currently in the 'night'.
+ *
+ * @return true if we are at night, false if the day.
+ */
+ boolean isNight() {
+ final TwilightState state = sTwilightState;
+
+ if (isStateValid(state)) {
+ // If the current twilight state is still valid, use it
+ return state.isNight;
+ }
+
+ // Else, we will try and grab the last known location
+ final Location location = getLastKnownLocation();
+ if (location != null) {
+ updateState(location);
+ return state.isNight;
+ }
+
+ Log.i(TAG, "Could not get last known location. This is probably because the app does not"
+ + " have any location permissions. Falling back to hardcoded"
+ + " sunrise/sunset values.");
+
+ // If we don't have a location, we'll use our hardcoded sunrise/sunset values.
+ // These aren't great, but it's better than nothing.
+ Calendar calendar = Calendar.getInstance();
+ final int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ return hour < SUNRISE || hour >= SUNSET;
+ }
+
+ private Location getLastKnownLocation() {
+ Location coarseLocation = null;
+ Location fineLocation = null;
+
+ int permission = PermissionChecker.checkSelfPermission(mContext,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+ if (permission == PermissionChecker.PERMISSION_GRANTED) {
+ coarseLocation = getLastKnownLocationForProvider(LocationManager.NETWORK_PROVIDER);
+ }
+
+ permission = PermissionChecker.checkSelfPermission(mContext,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
+ if (permission == PermissionChecker.PERMISSION_GRANTED) {
+ fineLocation = getLastKnownLocationForProvider(LocationManager.GPS_PROVIDER);
+ }
+
+ if (coarseLocation != null && fineLocation != null) {
+ // If we have both a fine and coarse location, use the latest
+ if (fineLocation.getTime() > coarseLocation.getTime()) {
+ return fineLocation;
+ } else {
+ return coarseLocation;
+ }
+ } else {
+ // Else, return the non-null one (if there is one)
+ return fineLocation != null ? fineLocation : coarseLocation;
+ }
+ }
+
+ private Location getLastKnownLocationForProvider(String provider) {
+ if (mLocationManager != null) {
+ try {
+ if (mLocationManager.isProviderEnabled(provider)) {
+ return mLocationManager.getLastKnownLocation(provider);
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "Failed to get last known location", e);
+ }
+ }
+ return null;
+ }
+
+ private boolean isStateValid(TwilightState state) {
+ return state != null && state.nextUpdate > System.currentTimeMillis();
+ }
+
+ private void updateState(@NonNull Location location) {
+ final TwilightState state = sTwilightState;
+ final long now = System.currentTimeMillis();
+ final TwilightCalculator calculator = TwilightCalculator.getInstance();
+
+ // calculate yesterday's twilight
+ calculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS,
+ location.getLatitude(), location.getLongitude());
+ final long yesterdaySunset = calculator.sunset;
+
+ // calculate today's twilight
+ calculator.calculateTwilight(now, location.getLatitude(), location.getLongitude());
+ final boolean isNight = (calculator.state == TwilightCalculator.NIGHT);
+ final long todaySunrise = calculator.sunrise;
+ final long todaySunset = calculator.sunset;
+
+ // calculate tomorrow's twilight
+ calculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS,
+ location.getLatitude(), location.getLongitude());
+ final long tomorrowSunrise = calculator.sunrise;
+
+ // Set next update
+ long nextUpdate = 0;
+ if (todaySunrise == -1 || todaySunset == -1) {
+ // In the case the day or night never ends the update is scheduled 12 hours later.
+ nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS;
+ } else {
+ if (now > todaySunset) {
+ nextUpdate += tomorrowSunrise;
+ } else if (now > todaySunrise) {
+ nextUpdate += todaySunset;
+ } else {
+ nextUpdate += todaySunrise;
+ }
+ // add some extra time to be on the safe side.
+ nextUpdate += DateUtils.MINUTE_IN_MILLIS;
+ }
+
+ // Update the twilight state
+ state.isNight = isNight;
+ state.yesterdaySunset = yesterdaySunset;
+ state.todaySunrise = todaySunrise;
+ state.todaySunset = todaySunset;
+ state.tomorrowSunrise = tomorrowSunrise;
+ state.nextUpdate = nextUpdate;
+ }
+
+ /**
+ * Describes whether it is day or night.
+ */
+ private static class TwilightState {
+ boolean isNight;
+ long yesterdaySunset;
+ long todaySunrise;
+ long todaySunset;
+ long tomorrowSunrise;
+ long nextUpdate;
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableUtils.java b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableUtils.java
new file mode 100644
index 0000000..ffe68d5
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/graphics/drawable/DrawableUtils.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.graphics.drawable;
+
+import android.graphics.PorterDuff;
+import android.os.Build;
+
+/**
+ * @hide
+ */
+public class DrawableUtils {
+
+ public static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) {
+ switch (value) {
+ case 3: return PorterDuff.Mode.SRC_OVER;
+ case 5: return PorterDuff.Mode.SRC_IN;
+ case 9: return PorterDuff.Mode.SRC_ATOP;
+ case 14: return PorterDuff.Mode.MULTIPLY;
+ case 15: return PorterDuff.Mode.SCREEN;
+ case 16: return Build.VERSION.SDK_INT >= 11 ? PorterDuff.Mode.valueOf("ADD")
+ : defaultMode;
+ default: return defaultMode;
+ }
+ }
+
+}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java b/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
index 189260a..41e684a 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
+++ b/v7/appcompat/src/android/support/v7/internal/app/NavItemSelectedListener.java
@@ -18,8 +18,8 @@
package android.support.v7.internal.app;
import android.support.v7.app.ActionBar;
-import android.support.v7.internal.widget.AdapterViewCompat;
import android.view.View;
+import android.widget.AdapterView;
/**
* Wrapper to adapt the ActionBar.OnNavigationListener in an AdapterView.OnItemSelectedListener
@@ -27,7 +27,7 @@
*
* @hide
*/
-class NavItemSelectedListener implements AdapterViewCompat.OnItemSelectedListener {
+class NavItemSelectedListener implements AdapterView.OnItemSelectedListener {
private final ActionBar.OnNavigationListener mListener;
public NavItemSelectedListener(ActionBar.OnNavigationListener listener) {
@@ -35,14 +35,14 @@
}
@Override
- public void onItemSelected(AdapterViewCompat<?> parent, View view, int position, long id) {
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mListener != null) {
mListener.onNavigationItemSelected(position, id);
}
}
@Override
- public void onNothingSelected(AdapterViewCompat<?> parent) {
+ public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java b/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
index 1781015..c8ef657 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
+++ b/v7/appcompat/src/android/support/v7/internal/app/ToolbarActionBar.java
@@ -22,8 +22,8 @@
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowCompat;
import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatDelegate;
import android.support.v7.appcompat.R;
import android.support.v7.internal.view.WindowCallbackWrapper;
import android.support.v7.internal.view.menu.ListMenuPresenter;
@@ -92,7 +92,9 @@
@Override
public void setCustomView(View view, LayoutParams layoutParams) {
- view.setLayoutParams(layoutParams);
+ if (view != null) {
+ view.setLayoutParams(layoutParams);
+ }
mDecorToolbar.setCustomView(view);
}
@@ -577,7 +579,7 @@
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
if (mWindowCallback != null) {
- mWindowCallback.onMenuOpened(WindowCompat.FEATURE_ACTION_BAR, subMenu);
+ mWindowCallback.onMenuOpened(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, subMenu);
return true;
}
return false;
@@ -592,7 +594,7 @@
mClosingActionMenu = true;
mDecorToolbar.dismissPopupMenus();
if (mWindowCallback != null) {
- mWindowCallback.onPanelClosed(WindowCompat.FEATURE_ACTION_BAR, menu);
+ mWindowCallback.onPanelClosed(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, menu);
}
mClosingActionMenu = false;
}
@@ -626,10 +628,10 @@
public void onMenuModeChange(MenuBuilder menu) {
if (mWindowCallback != null) {
if (mDecorToolbar.isOverflowMenuShowing()) {
- mWindowCallback.onPanelClosed(WindowCompat.FEATURE_ACTION_BAR, menu);
+ mWindowCallback.onPanelClosed(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, menu);
} else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL,
null, menu)) {
- mWindowCallback.onMenuOpened(WindowCompat.FEATURE_ACTION_BAR, menu);
+ mWindowCallback.onMenuOpened(AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR, menu);
}
}
}
diff --git a/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java b/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
index 2557d06..e76f658 100644
--- a/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/android/support/v7/internal/app/WindowDecorActionBar.java
@@ -34,8 +34,8 @@
import android.support.v7.app.ActionBar;
import android.support.v7.appcompat.R;
import android.support.v7.internal.view.ActionBarPolicy;
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
import android.support.v7.internal.view.SupportMenuInflater;
+import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuPopupHelper;
import android.support.v7.internal.view.menu.SubMenuBuilder;
@@ -43,8 +43,8 @@
import android.support.v7.internal.widget.ActionBarContextView;
import android.support.v7.internal.widget.ActionBarOverlayLayout;
import android.support.v7.internal.widget.DecorToolbar;
-import android.support.v7.internal.widget.TintManager;
import android.support.v7.internal.widget.ScrollingTabContainerView;
+import android.support.v7.internal.widget.TintManager;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
@@ -57,7 +57,10 @@
import android.view.ViewParent;
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.widget.SpinnerAdapter;
import java.lang.ref.WeakReference;
@@ -66,9 +69,6 @@
/**
* WindowDecorActionBar is the ActionBar implementation used
* by devices of all screen sizes as part of the window decor layout.
- * If it detects a compatible decor, it will split contextual modes
- * across both the ActionBarView at the top of the screen and
- * a horizontal LinearLayout at the bottom which is normally hidden.
*
* @hide
*/
@@ -76,6 +76,9 @@
ActionBarOverlayLayout.ActionBarVisibilityCallback {
private static final String TAG = "WindowDecorActionBar";
+ private static final Interpolator sHideInterpolator = new AccelerateInterpolator();
+ private static final Interpolator sShowInterpolator = new DecelerateInterpolator();
+
/**
* Only allow show/hide animations on ICS+, as that is what ViewPropertyAnimatorCompat supports
*/
@@ -90,7 +93,6 @@
private ActionBarContainer mContainerView;
private DecorToolbar mDecorToolbar;
private ActionBarContextView mContextView;
- private ActionBarContainer mSplitView;
private View mContentView;
private ScrollingTabContainerView mTabScrollView;
@@ -109,12 +111,12 @@
private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
new ArrayList<OnMenuVisibilityListener>();
- private static final int CONTEXT_DISPLAY_NORMAL = 0;
- private static final int CONTEXT_DISPLAY_SPLIT = 1;
-
private static final int INVALID_POSITION = -1;
- private int mContextDisplayMode;
+ // The fade duration for toolbar and action bar when entering/exiting action mode.
+ private static final long FADE_OUT_DURATION_MS = 100;
+ private static final long FADE_IN_DURATION_MS = 200;
+
private boolean mHasEmbeddedTabs;
private int mCurWindowVisibility = View.VISIBLE;
@@ -139,9 +141,6 @@
ViewCompat.setTranslationY(mContentView, 0f);
ViewCompat.setTranslationY(mContainerView, 0f);
}
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
- mSplitView.setVisibility(View.GONE);
- }
mContainerView.setVisibility(View.GONE);
mContainerView.setTransitioning(false);
mCurrentShowAnim = null;
@@ -204,16 +203,12 @@
mContainerView = (ActionBarContainer) decor.findViewById(
R.id.action_bar_container);
- mSplitView = (ActionBarContainer) decor.findViewById(R.id.split_action_bar);
-
if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with a compatible window decor layout");
}
mContext = mDecorToolbar.getContext();
- mContextDisplayMode = mDecorToolbar.isSplit() ?
- CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
// This was initially read from the action bar style
final int current = mDecorToolbar.getDisplayOptions();
@@ -253,9 +248,6 @@
@Override
public void setElevation(float elevation) {
ViewCompat.setElevation(mContainerView, elevation);
- if (mSplitView != null) {
- ViewCompat.setElevation(mSplitView, elevation);
- }
}
@Override
@@ -474,9 +466,7 @@
}
public void setSplitBackgroundDrawable(Drawable d) {
- if (mSplitView != null) {
- mSplitView.setSplitBackground(d);
- }
+ // no-op. We don't support split action bars
}
public View getCustomView() {
@@ -511,15 +501,6 @@
mode.invalidate();
mContextView.initForMode(mode);
animateToMode(true);
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
- // TODO animate this
- if (mSplitView.getVisibility() != View.VISIBLE) {
- mSplitView.setVisibility(View.VISIBLE);
- if (mOverlayLayout != null) {
- ViewCompat.requestApplyInsets(mOverlayLayout);
- }
- }
- }
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
mActionMode = mode;
return mode;
@@ -793,13 +774,7 @@
ViewCompat.setTranslationY(mContentView, startingY);
anim.play(ViewCompat.animate(mContentView).translationY(0f));
}
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
- ViewCompat.setTranslationY(mSplitView, mSplitView.getHeight());
- mSplitView.setVisibility(View.VISIBLE);
- anim.play(ViewCompat.animate(mSplitView).translationY(0f));
- }
- anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
- android.R.anim.decelerate_interpolator));
+ anim.setInterpolator(sShowInterpolator);
anim.setDuration(250);
// If this is being shown from the system, add a small delay.
// This is because we will also be animating in the status bar,
@@ -817,11 +792,6 @@
if (mContentAnimations && mContentView != null) {
ViewCompat.setTranslationY(mContentView, 0);
}
- if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
- ViewCompat.setAlpha(mSplitView, 1f);
- ViewCompat.setTranslationY(mSplitView, 0);
- mSplitView.setVisibility(View.VISIBLE);
- }
mShowListener.onAnimationEnd(null);
}
if (mOverlayLayout != null) {
@@ -851,12 +821,7 @@
if (mContentAnimations && mContentView != null) {
anim.play(ViewCompat.animate(mContentView).translationY(endingY));
}
- if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
- ViewCompat.setAlpha(mSplitView, 1f);
- anim.play(ViewCompat.animate(mSplitView).translationY(mSplitView.getHeight()));
- }
- anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
- android.R.anim.accelerate_interpolator));
+ anim.setInterpolator(sHideInterpolator);
anim.setDuration(250);
anim.setListener(mHideListener);
mCurrentShowAnim = anim;
@@ -879,8 +844,21 @@
hideForActionMode();
}
- mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
- mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
+ ViewPropertyAnimatorCompat fadeIn, fadeOut;
+ if (toActionMode) {
+ fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE,
+ FADE_OUT_DURATION_MS);
+ fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE,
+ FADE_IN_DURATION_MS);
+ } else {
+ fadeIn = mDecorToolbar.setupAnimatorToVisibility(View.VISIBLE,
+ FADE_IN_DURATION_MS);
+ fadeOut = mContextView.setupAnimatorToVisibility(View.GONE,
+ FADE_OUT_DURATION_MS);
+ }
+ ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet();
+ set.playSequentially(fadeOut, fadeIn);
+ set.start();
// mTabScrollView's visibility is not affected by action mode.
}
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java b/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
index e414203..d8932ee 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/ContextThemeWrapper.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
+import android.support.annotation.StyleRes;
import android.support.v7.appcompat.R;
import android.view.LayoutInflater;
@@ -33,15 +34,22 @@
private Resources.Theme mTheme;
private LayoutInflater mInflater;
- public ContextThemeWrapper(Context base, int themeres) {
+ public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
super(base);
- mThemeResource = themeres;
+ mThemeResource = themeResId;
+ }
+
+ public ContextThemeWrapper(Context base, Resources.Theme theme) {
+ super(base);
+ mTheme = theme;
}
@Override
public void setTheme(int resid) {
- mThemeResource = resid;
- initializeTheme();
+ if (mThemeResource != resid) {
+ mThemeResource = resid;
+ initializeTheme();
+ }
}
public int getThemeResId() {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java b/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
index 84a07da..7bc3978 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
@@ -496,6 +496,7 @@
try {
Class<?> clazz = mContext.getClassLoader().loadClass(className);
Constructor<?> constructor = clazz.getConstructor(constructorSignature);
+ constructor.setAccessible(true);
return (T) constructor.newInstance(arguments);
} catch (Exception e) {
Log.w(LOG_TAG, "Cannot instantiate class: " + className, e);
diff --git a/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java b/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
index 457e1b1..ec1d567 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/ViewPropertyAnimatorCompatSet.java
@@ -51,6 +51,14 @@
return this;
}
+ public ViewPropertyAnimatorCompatSet playSequentially(ViewPropertyAnimatorCompat anim1,
+ ViewPropertyAnimatorCompat anim2) {
+ mAnimators.add(anim1);
+ anim2.setStartDelay(anim1.getDuration());
+ mAnimators.add(anim2);
+ return this;
+ }
+
public void start() {
if (mIsStarted) return;
for (ViewPropertyAnimatorCompat animator : mAnimators) {
diff --git a/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java b/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
index d799d00..900d304 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/WindowCallbackWrapper.java
@@ -21,6 +21,7 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.SearchEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@@ -130,6 +131,11 @@
}
@Override
+ public boolean onSearchRequested(SearchEvent searchEvent) {
+ return mWrapped.onSearchRequested(searchEvent);
+ }
+
+ @Override
public boolean onSearchRequested() {
return mWrapped.onSearchRequested();
}
@@ -140,6 +146,11 @@
}
@Override
+ public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) {
+ return mWrapped.onWindowStartingActionMode(callback, type);
+ }
+
+ @Override
public void onActionModeStarted(ActionMode mode) {
mWrapped.onActionModeStarted(mode);
}
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
index af7deef..bdcc79a 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuPopupHelper.java
@@ -121,6 +121,10 @@
mDropDownGravity = gravity;
}
+ public int getGravity() {
+ return mDropDownGravity;
+ }
+
public void show() {
if (!tryShow()) {
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java b/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
index 0d06065..a3518f5 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/AbsActionBarView.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.support.v7.internal.widget;
import android.content.Context;
@@ -23,7 +24,6 @@
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
import android.support.v7.widget.ActionMenuPresenter;
import android.support.v7.widget.ActionMenuView;
import android.util.AttributeSet;
@@ -31,12 +31,8 @@
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
abstract class AbsActionBarView extends ViewGroup {
- private static final Interpolator sAlphaInterpolator = new DecelerateInterpolator();
-
private static final int FADE_DURATION = 200;
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
@@ -46,9 +42,6 @@
protected ActionMenuView mMenuView;
protected ActionMenuPresenter mActionMenuPresenter;
- protected ViewGroup mSplitView;
- protected boolean mSplitActionBar;
- protected boolean mSplitWhenNarrow;
protected int mContentHeight;
protected ViewPropertyAnimatorCompat mVisibilityAnim;
@@ -91,22 +84,6 @@
}
}
- /**
- * Sets whether the bar should be split right now, no questions asked.
- * @param split true if the bar should split
- */
- public void setSplitToolbar(boolean split) {
- mSplitActionBar = split;
- }
-
- /**
- * Sets whether the bar should split if we enter a narrow screen configuration.
- * @param splitWhenNarrow true if the bar should check to split after a config change
- */
- public void setSplitWhenNarrow(boolean splitWhenNarrow) {
- mSplitWhenNarrow = splitWhenNarrow;
- }
-
public void setContentHeight(int height) {
mContentHeight = height;
requestLayout();
@@ -116,10 +93,6 @@
return mContentHeight;
}
- public void setSplitView(ViewGroup splitView) {
- mSplitView = splitView;
- }
-
/**
* @return Current visibility or if animating, the visibility being animated to.
*/
@@ -130,46 +103,39 @@
return getVisibility();
}
- public void animateToVisibility(int visibility) {
+ public ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration) {
if (mVisibilityAnim != null) {
mVisibilityAnim.cancel();
}
+
if (visibility == VISIBLE) {
if (getVisibility() != VISIBLE) {
ViewCompat.setAlpha(this, 0f);
- if (mSplitView != null && mMenuView != null) {
- ViewCompat.setAlpha(mMenuView, 0f);
- }
}
ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f);
- anim.setDuration(FADE_DURATION);
- anim.setInterpolator(sAlphaInterpolator);
- if (mSplitView != null && mMenuView != null) {
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet();
- ViewPropertyAnimatorCompat splitAnim = ViewCompat.animate(mMenuView).alpha(1f);
- splitAnim.setDuration(FADE_DURATION);
- set.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
- set.play(anim).play(splitAnim);
- set.start();
- } else {
- anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
- anim.start();
- }
+ anim.setDuration(duration);
+ anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
+ return anim;
} else {
ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f);
- anim.setDuration(FADE_DURATION);
- anim.setInterpolator(sAlphaInterpolator);
- if (mSplitView != null && mMenuView != null) {
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet();
- ViewPropertyAnimatorCompat splitAnim = ViewCompat.animate(mMenuView).alpha(0f);
- splitAnim.setDuration(FADE_DURATION);
- set.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
- set.play(anim).play(splitAnim);
- set.start();
- } else {
- anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
- anim.start();
+ anim.setDuration(duration);
+ anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility));
+ return anim;
+ }
+ }
+
+ public void animateToVisibility(int visibility) {
+ ViewPropertyAnimatorCompat anim = setupAnimatorToVisibility(visibility, FADE_DURATION);
+ anim.start();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ if (visibility != getVisibility()) {
+ if (mVisibilityAnim != null) {
+ mVisibilityAnim.cancel();
}
+ super.setVisibility(visibility);
}
}
@@ -265,7 +231,7 @@
@Override
public void onAnimationStart(View view) {
- setVisibility(VISIBLE);
+ AbsActionBarView.super.setVisibility(VISIBLE);
mCanceled = false;
}
@@ -274,10 +240,7 @@
if (mCanceled) return;
mVisibilityAnim = null;
- setVisibility(mFinalVisibility);
- if (mSplitView != null && mMenuView != null) {
- mMenuView.setVisibility(mFinalVisibility);
- }
+ AbsActionBarView.super.setVisibility(mFinalVisibility);
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AbsSpinnerCompat.java b/v7/appcompat/src/android/support/v7/internal/widget/AbsSpinnerCompat.java
deleted file mode 100644
index 0ec8e7a..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/AbsSpinnerCompat.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.internal.widget;
-
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.graphics.Rect;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SpinnerAdapter;
-
-/**
- * An abstract base class for spinner widgets. SDK users will probably not
- * need to use this class.
- */
-abstract class AbsSpinnerCompat extends AdapterViewCompat<SpinnerAdapter> {
- SpinnerAdapter mAdapter;
-
- int mHeightMeasureSpec;
- int mWidthMeasureSpec;
-
- int mSelectionLeftPadding = 0;
- int mSelectionTopPadding = 0;
- int mSelectionRightPadding = 0;
- int mSelectionBottomPadding = 0;
- final Rect mSpinnerPadding = new Rect();
-
- final RecycleBin mRecycler = new RecycleBin();
- private DataSetObserver mDataSetObserver;
-
- /** Temporary frame to hold a child View's frame rectangle */
- private Rect mTouchFrame;
-
- AbsSpinnerCompat(Context context) {
- super(context);
- initAbsSpinner();
- }
-
- AbsSpinnerCompat(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- AbsSpinnerCompat(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- initAbsSpinner();
- }
-
- /**
- * Common code for different constructor flavors
- */
- private void initAbsSpinner() {
- setFocusable(true);
- setWillNotDraw(false);
- }
-
- /**
- * The Adapter is used to provide the data which backs this Spinner.
- * It also provides methods to transform spinner items based on their position
- * relative to the selected item.
- * @param adapter The SpinnerAdapter to use for this Spinner
- */
- @Override
- public void setAdapter(SpinnerAdapter adapter) {
- if (null != mAdapter) {
- mAdapter.unregisterDataSetObserver(mDataSetObserver);
- resetList();
- }
-
- mAdapter = adapter;
-
- mOldSelectedPosition = INVALID_POSITION;
- mOldSelectedRowId = INVALID_ROW_ID;
-
- if (mAdapter != null) {
- mOldItemCount = mItemCount;
- mItemCount = mAdapter.getCount();
- checkFocus();
-
- mDataSetObserver = new AdapterDataSetObserver();
- mAdapter.registerDataSetObserver(mDataSetObserver);
-
- int position = mItemCount > 0 ? 0 : INVALID_POSITION;
-
- setSelectedPositionInt(position);
- setNextSelectedPositionInt(position);
-
- if (mItemCount == 0) {
- // Nothing selected
- checkSelectionChanged();
- }
-
- } else {
- checkFocus();
- resetList();
- // Nothing selected
- checkSelectionChanged();
- }
-
- requestLayout();
- }
-
- /**
- * Clear out all children from the list
- */
- void resetList() {
- mDataChanged = false;
- mNeedSync = false;
-
- removeAllViewsInLayout();
- mOldSelectedPosition = INVALID_POSITION;
- mOldSelectedRowId = INVALID_ROW_ID;
-
- setSelectedPositionInt(INVALID_POSITION);
- setNextSelectedPositionInt(INVALID_POSITION);
- invalidate();
- }
-
- /**
- * @see android.view.View#measure(int, int)
- *
- * Figure out the dimensions of this Spinner. The width comes from
- * the widthMeasureSpec as Spinnners can't have their width set to
- * UNSPECIFIED. The height is based on the height of the selected item
- * plus padding.
- */
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSize;
- int heightSize;
-
- final int paddingLeft = getPaddingLeft();
- final int paddingTop = getPaddingTop();
- final int paddingRight = getPaddingRight();
- final int paddingBottom = getPaddingBottom();
-
- mSpinnerPadding.left = paddingLeft > mSelectionLeftPadding ? paddingLeft
- : mSelectionLeftPadding;
- mSpinnerPadding.top = paddingTop > mSelectionTopPadding ? paddingTop
- : mSelectionTopPadding;
- mSpinnerPadding.right = paddingRight > mSelectionRightPadding ? paddingRight
- : mSelectionRightPadding;
- mSpinnerPadding.bottom = paddingBottom > mSelectionBottomPadding ? paddingBottom
- : mSelectionBottomPadding;
-
- if (mDataChanged) {
- handleDataChanged();
- }
-
- int preferredHeight = 0;
- int preferredWidth = 0;
- boolean needsMeasuring = true;
-
- int selectedPosition = getSelectedItemPosition();
- if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) {
- // Try looking in the recycler. (Maybe we were measured once already)
- View view = mRecycler.get(selectedPosition);
- if (view == null) {
- // Make a new one
- view = mAdapter.getView(selectedPosition, null, this);
- }
-
- if (view != null) {
- // Put in recycler for re-measuring and/or layout
- mRecycler.put(selectedPosition, view);
-
- if (view.getLayoutParams() == null) {
- mBlockLayoutRequests = true;
- view.setLayoutParams(generateDefaultLayoutParams());
- mBlockLayoutRequests = false;
- }
- measureChild(view, widthMeasureSpec, heightMeasureSpec);
-
- preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom;
- preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right;
-
- needsMeasuring = false;
- }
- }
-
- if (needsMeasuring) {
- // No views -- just use padding
- preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom;
- if (widthMode == MeasureSpec.UNSPECIFIED) {
- preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right;
- }
- }
-
- preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight());
- preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth());
-
- heightSize = ViewCompat.resolveSizeAndState(preferredHeight, heightMeasureSpec, 0);
- widthSize = ViewCompat.resolveSizeAndState(preferredWidth, widthMeasureSpec, 0);
-
- setMeasuredDimension(widthSize, heightSize);
- mHeightMeasureSpec = heightMeasureSpec;
- mWidthMeasureSpec = widthMeasureSpec;
- }
-
- int getChildHeight(View child) {
- return child.getMeasuredHeight();
- }
-
- int getChildWidth(View child) {
- return child.getMeasuredWidth();
- }
-
- @Override
- protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
- return new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- void recycleAllViews() {
- final int childCount = getChildCount();
- final AbsSpinnerCompat.RecycleBin recycleBin = mRecycler;
- final int position = mFirstPosition;
-
- // All views go in recycler
- for (int i = 0; i < childCount; i++) {
- View v = getChildAt(i);
- int index = position + i;
- recycleBin.put(index, v);
- }
- }
-
- /**
- * Jump directly to a specific item in the adapter data.
- */
- public void setSelection(int position, boolean animate) {
- // Animate only if requested position is already on screen somewhere
- boolean shouldAnimate = animate && mFirstPosition <= position &&
- position <= mFirstPosition + getChildCount() - 1;
- setSelectionInt(position, shouldAnimate);
- }
-
- @Override
- public void setSelection(int position) {
- setNextSelectedPositionInt(position);
- requestLayout();
- invalidate();
- }
-
-
- /**
- * Makes the item at the supplied position selected.
- *
- * @param position Position to select
- * @param animate Should the transition be animated
- *
- */
- void setSelectionInt(int position, boolean animate) {
- if (position != mOldSelectedPosition) {
- mBlockLayoutRequests = true;
- int delta = position - mSelectedPosition;
- setNextSelectedPositionInt(position);
- layout(delta, animate);
- mBlockLayoutRequests = false;
- }
- }
-
- abstract void layout(int delta, boolean animate);
-
- @Override
- public View getSelectedView() {
- if (mItemCount > 0 && mSelectedPosition >= 0) {
- return getChildAt(mSelectedPosition - mFirstPosition);
- } else {
- return null;
- }
- }
-
- /**
- * Override to prevent spamming ourselves with layout requests
- * as we place views
- *
- * @see android.view.View#requestLayout()
- */
- @Override
- public void requestLayout() {
- if (!mBlockLayoutRequests) {
- super.requestLayout();
- }
- }
-
- @Override
- public SpinnerAdapter getAdapter() {
- return mAdapter;
- }
-
- @Override
- public int getCount() {
- return mItemCount;
- }
-
- /**
- * Maps a point to a position in the list.
- *
- * @param x X in local coordinate
- * @param y Y in local coordinate
- * @return The position of the item which contains the specified point, or
- * {@link #INVALID_POSITION} if the point does not intersect an item.
- */
- public int pointToPosition(int x, int y) {
- Rect frame = mTouchFrame;
- if (frame == null) {
- mTouchFrame = new Rect();
- frame = mTouchFrame;
- }
-
- final int count = getChildCount();
- for (int i = count - 1; i >= 0; i--) {
- View child = getChildAt(i);
- if (child.getVisibility() == View.VISIBLE) {
- child.getHitRect(frame);
- if (frame.contains(x, y)) {
- return mFirstPosition + i;
- }
- }
- }
- return INVALID_POSITION;
- }
-
- static class SavedState extends BaseSavedState {
- long selectedId;
- int position;
-
- /**
- * Constructor called from {@link AbsSpinnerCompat#onSaveInstanceState()}
- */
- SavedState(Parcelable superState) {
- super(superState);
- }
-
- /**
- * Constructor called from {@link #CREATOR}
- */
- SavedState(Parcel in) {
- super(in);
- selectedId = in.readLong();
- position = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeLong(selectedId);
- out.writeInt(position);
- }
-
- @Override
- public String toString() {
- return "AbsSpinner.SavedState{"
- + Integer.toHexString(System.identityHashCode(this))
- + " selectedId=" + selectedId
- + " position=" + position + "}";
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR
- = new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- Parcelable superState = super.onSaveInstanceState();
- SavedState ss = new SavedState(superState);
- ss.selectedId = getSelectedItemId();
- if (ss.selectedId >= 0) {
- ss.position = getSelectedItemPosition();
- } else {
- ss.position = INVALID_POSITION;
- }
- return ss;
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- SavedState ss = (SavedState) state;
-
- super.onRestoreInstanceState(ss.getSuperState());
-
- if (ss.selectedId >= 0) {
- mDataChanged = true;
- mNeedSync = true;
- mSyncRowId = ss.selectedId;
- mSyncPosition = ss.position;
- mSyncMode = SYNC_SELECTED_POSITION;
- requestLayout();
- }
- }
-
- class RecycleBin {
- private final SparseArray<View> mScrapHeap = new SparseArray<View>();
-
- public void put(int position, View v) {
- mScrapHeap.put(position, v);
- }
-
- View get(int position) {
- // System.out.print("Looking for " + position);
- View result = mScrapHeap.get(position);
- if (result != null) {
- // System.out.println(" HIT");
- mScrapHeap.delete(position);
- } else {
- // System.out.println(" MISS");
- }
- return result;
- }
-
- void clear() {
- final SparseArray<View> scrapHeap = mScrapHeap;
- final int count = scrapHeap.size();
- for (int i = 0; i < count; i++) {
- final View view = scrapHeap.valueAt(i);
- if (view != null) {
- removeDetachedView(view, true);
- }
- }
- scrapHeap.clear();
- }
- }
-}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java b/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
index 97a44ad..7c5d221 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/ActionBarContextView.java
@@ -17,32 +17,26 @@
package android.support.v7.internal.widget;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPropertyAnimatorCompat;
-import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet;
+import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.ActionMenuPresenter;
import android.support.v7.widget.ActionMenuView;
-import android.support.v7.internal.view.menu.MenuBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* @hide
*/
-public class ActionBarContextView extends AbsActionBarView implements ViewPropertyAnimatorListener {
+public class ActionBarContextView extends AbsActionBarView {
private static final String TAG = "ActionBarContextView";
private CharSequence mTitle;
@@ -55,18 +49,9 @@
private TextView mSubtitleView;
private int mTitleStyleRes;
private int mSubtitleStyleRes;
- private Drawable mSplitBackground;
private boolean mTitleOptional;
private int mCloseItemLayout;
- private ViewPropertyAnimatorCompatSet mCurrentAnimation;
- private boolean mAnimateInOnLayout;
- private int mAnimationMode;
-
- private static final int ANIMATE_IDLE = 0;
- private static final int ANIMATE_IN = 1;
- private static final int ANIMATE_OUT = 2;
-
public ActionBarContextView(Context context) {
this(context, null);
}
@@ -90,9 +75,6 @@
mContentHeight = a.getLayoutDimension(
R.styleable.ActionMode_height, 0);
- mSplitBackground = a.getDrawable(
- R.styleable.ActionMode_backgroundSplit);
-
mCloseItemLayout = a.getResourceId(
R.styleable.ActionMode_closeItemLayout,
R.layout.abc_action_mode_close_item_material);
@@ -109,39 +91,6 @@
}
}
- @Override
- public void setSplitToolbar(boolean split) {
- if (mSplitActionBar != split) {
- if (mActionMenuPresenter != null) {
- // Mode is already active; move everything over and adjust the menu itself.
- final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT);
- if (!split) {
- mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(null);
- final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
- if (oldParent != null) oldParent.removeView(mMenuView);
- addView(mMenuView, layoutParams);
- } else {
- // Allow full screen width in split mode.
- mActionMenuPresenter.setWidthLimit(
- getContext().getResources().getDisplayMetrics().widthPixels, true);
- // No limit to the item count; use whatever will fit.
- mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
- // Span the whole width
- layoutParams.width = LayoutParams.MATCH_PARENT;
- layoutParams.height = mContentHeight;
- mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(mSplitBackground);
- final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
- if (oldParent != null) oldParent.removeView(mMenuView);
- mSplitView.addView(mMenuView, layoutParams);
- }
- }
- super.setSplitToolbar(split);
- }
- }
-
public void setContentHeight(int height) {
mContentHeight = height;
}
@@ -151,7 +100,7 @@
removeView(mCustomView);
}
mCustomView = view;
- if (mTitleLayout != null) {
+ if (view != null && mTitleLayout != null) {
removeView(mTitleLayout);
mTitleLayout = null;
}
@@ -231,62 +180,23 @@
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
- if (!mSplitActionBar) {
- menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
- mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(null);
- addView(mMenuView, layoutParams);
- } else {
- // Allow full screen width in split mode.
- mActionMenuPresenter.setWidthLimit(
- getContext().getResources().getDisplayMetrics().widthPixels, true);
- // No limit to the item count; use whatever will fit.
- mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
- // Span the whole width
- layoutParams.width = LayoutParams.MATCH_PARENT;
- layoutParams.height = mContentHeight;
- menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
- mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(mSplitBackground);
- mSplitView.addView(mMenuView, layoutParams);
- }
-
- mAnimateInOnLayout = true;
+ menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
+ mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+ mMenuView.setBackgroundDrawable(null);
+ addView(mMenuView, layoutParams);
}
public void closeMode() {
- if (mAnimationMode == ANIMATE_OUT) {
- // Called again during close; just finish what we were doing.
- return;
- }
if (mClose == null) {
killMode();
return;
}
-
- finishAnimation();
- mAnimationMode = ANIMATE_OUT;
- mCurrentAnimation = makeOutAnimation();
- mCurrentAnimation.start();
- }
-
- private void finishAnimation() {
- final ViewPropertyAnimatorCompatSet a = mCurrentAnimation;
- if (a != null) {
- mCurrentAnimation = null;
- a.cancel();
- }
}
public void killMode() {
- finishAnimation();
removeAllViews();
- if (mSplitView != null) {
- mSplitView.removeView(mMenuView);
- }
mCustomView = null;
mMenuView = null;
- mAnimateInOnLayout = false;
}
@Override
@@ -405,60 +315,6 @@
}
}
- private ViewPropertyAnimatorCompatSet makeInAnimation() {
- ViewCompat.setTranslationX(mClose, -mClose.getWidth() -
- ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
- ViewPropertyAnimatorCompat buttonAnimator = ViewCompat.animate(mClose).translationX(0);
- buttonAnimator.setDuration(200);
- buttonAnimator.setListener(this);
- buttonAnimator.setInterpolator(new DecelerateInterpolator());
-
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet();
- set.play(buttonAnimator);
-
- if (mMenuView != null) {
- final int count = mMenuView.getChildCount();
- if (count > 0) {
- for (int i = count - 1, j = 0; i >= 0; i--, j++) {
- View child = mMenuView.getChildAt(i);
- ViewCompat.setScaleY(child, 0);
- ViewPropertyAnimatorCompat a = ViewCompat.animate(child).scaleY(1);
- a.setDuration(300);
- set.play(a);
- }
- }
- }
-
- return set;
- }
-
- private ViewPropertyAnimatorCompatSet makeOutAnimation() {
- ViewPropertyAnimatorCompat buttonAnimator = ViewCompat.animate(mClose)
- .translationX(-mClose.getWidth() -
- ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
- buttonAnimator.setDuration(200);
- buttonAnimator.setListener(this);
- buttonAnimator.setInterpolator(new DecelerateInterpolator());
-
- ViewPropertyAnimatorCompatSet set = new ViewPropertyAnimatorCompatSet();
- set.play(buttonAnimator);
-
- if (mMenuView != null) {
- final int count = mMenuView.getChildCount();
- if (count > 0) {
- for (int i = 0; i < 0; i++) {
- View child = mMenuView.getChildAt(i);
- ViewCompat.setScaleY(child, 1);
- ViewPropertyAnimatorCompat a = ViewCompat.animate(child).scaleY(0);
- a.setDuration(300);
- set.play(a);
- }
- }
- }
-
- return set;
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this);
@@ -473,13 +329,6 @@
x = next(x, startMargin, isLayoutRtl);
x += positionChild(mClose, x, y, contentHeight, isLayoutRtl);
x = next(x, endMargin, isLayoutRtl);
-
- if (mAnimateInOnLayout) {
- mAnimationMode = ANIMATE_IN;
- mCurrentAnimation = makeInAnimation();
- mCurrentAnimation.start();
- mAnimateInOnLayout = false;
- }
}
if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) {
@@ -498,22 +347,6 @@
}
@Override
- public void onAnimationStart(View view) {
- }
-
- @Override
- public void onAnimationEnd(View view) {
- if (mAnimationMode == ANIMATE_OUT) {
- killMode();
- }
- mAnimationMode = ANIMATE_IDLE;
- }
-
- @Override
- public void onAnimationCancel(View view) {
- }
-
- @Override
public boolean shouldDelayChildPressedState() {
return false;
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java b/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
index 36d70bc..d647d7f 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/ActionBarOverlayLayout.java
@@ -31,6 +31,7 @@
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.support.v4.widget.ScrollerCompat;
+import android.support.v7.app.AppCompatDelegate;
import android.support.v7.appcompat.R;
import android.support.v7.internal.VersionUtils;
import android.support.v7.internal.view.menu.MenuPresenter;
@@ -58,7 +59,6 @@
// The main UI elements that we handle the layout of.
private ContentFrameLayout mContent;
- private ActionBarContainer mActionBarBottom;
private ActionBarContainer mActionBarTop;
// Some interior UI elements.
@@ -88,7 +88,6 @@
private ScrollerCompat mFlingEstimator;
private ViewPropertyAnimatorCompat mCurrentActionBarTopAnimator;
- private ViewPropertyAnimatorCompat mCurrentActionBarBottomAnimator;
private final ViewPropertyAnimatorListener mTopAnimatorListener
= new ViewPropertyAnimatorListenerAdapter() {
@@ -105,30 +104,11 @@
}
};
- private final ViewPropertyAnimatorListener mBottomAnimatorListener =
- new ViewPropertyAnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(View view) {
- mCurrentActionBarBottomAnimator = null;
- mAnimatingForFling = false;
- }
-
- @Override
- public void onAnimationCancel(View view) {
- mCurrentActionBarBottomAnimator = null;
- mAnimatingForFling = false;
- }
- };
-
private final Runnable mRemoveActionBarHideOffset = new Runnable() {
public void run() {
haltActionBarHideOffsetAnimations();
mCurrentActionBarTopAnimator = ViewCompat.animate(mActionBarTop).translationY(0)
.setListener(mTopAnimatorListener);
- if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
- mCurrentActionBarBottomAnimator = ViewCompat.animate(mActionBarBottom).translationY(0)
- .setListener(mBottomAnimatorListener);
- }
}
};
@@ -138,11 +118,6 @@
mCurrentActionBarTopAnimator = ViewCompat.animate(mActionBarTop)
.translationY(-mActionBarTop.getHeight())
.setListener(mTopAnimatorListener);
- if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
- mCurrentActionBarBottomAnimator = ViewCompat.animate(mActionBarBottom)
- .translationY(mActionBarBottom.getHeight())
- .setListener(mBottomAnimatorListener);
- }
}
};
@@ -310,11 +285,8 @@
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
final Rect systemInsets = insets;
- // The top and bottom action bars are always within the content area.
+ // The top action bar is always within the content area.
boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
- if (mActionBarBottom != null) {
- changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
- }
mBaseInnerInsets.set(systemInsets);
ViewUtils.computeFitSystemWindows(this, mBaseInnerInsets, mBaseContentInsets);
@@ -374,18 +346,6 @@
childState = ViewUtils.combineMeasuredStates(childState,
ViewCompat.getMeasuredState(mActionBarTop));
- // xlarge screen layout doesn't have bottom action bar.
- if (mActionBarBottom != null) {
- measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0);
- lp = (LayoutParams) mActionBarBottom.getLayoutParams();
- maxWidth = Math.max(maxWidth,
- mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
- maxHeight = Math.max(maxHeight,
- mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
- childState = ViewUtils.combineMeasuredStates(childState,
- ViewCompat.getMeasuredState(mActionBarBottom));
- }
-
final int vis = ViewCompat.getWindowSystemUiVisibility(this);
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
@@ -406,17 +366,6 @@
topInset = mActionBarTop.getMeasuredHeight();
}
- if (mDecorToolbar.isSplit()) {
- // If action bar is split, adjust bottom insets for it.
- if (mActionBarBottom != null) {
- if (stable) {
- bottomInset = mActionBarHeight;
- } else {
- bottomInset = mActionBarBottom.getMeasuredHeight();
- }
- }
- }
-
// If the window has not requested system UI layout flags, we need to
// make sure its content is not being covered by system UI... though it
// will still be covered by the action bar if they have requested it to
@@ -483,12 +432,7 @@
final int height = child.getMeasuredHeight();
int childLeft = parentLeft + lp.leftMargin;
- int childTop;
- if (child == mActionBarBottom) {
- childTop = parentBottom - height - lp.bottomMargin;
- } else {
- childTop = parentTop + lp.topMargin;
- }
+ int childTop = parentTop + lp.topMargin;
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
@@ -586,7 +530,6 @@
mContent = (ContentFrameLayout) findViewById(R.id.action_bar_activity_content);
mActionBarTop = (ActionBarContainer) findViewById(R.id.action_bar_container);
mDecorToolbar = getDecorToolbar(findViewById(R.id.action_bar));
- mActionBarBottom = (ActionBarContainer) findViewById(R.id.split_action_bar);
}
}
@@ -624,12 +567,6 @@
final int topHeight = mActionBarTop.getHeight();
offset = Math.max(0, Math.min(offset, topHeight));
ViewCompat.setTranslationY(mActionBarTop, -offset);
- if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
- // Match the hide offset proportionally for a split bar
- final float fOffset = (float) offset / topHeight;
- final int bOffset = (int) (mActionBarBottom.getHeight() * fOffset);
- ViewCompat.setTranslationY(mActionBarBottom, bOffset);
- }
}
private void haltActionBarHideOffsetAnimations() {
@@ -638,9 +575,6 @@
if (mCurrentActionBarTopAnimator != null) {
mCurrentActionBarTopAnimator.cancel();
}
- if (mCurrentActionBarBottomAnimator != null) {
- mCurrentActionBarBottomAnimator.cancel();
- }
}
private void postRemoveActionBarHideOffset() {
@@ -697,7 +631,7 @@
case Window.FEATURE_INDETERMINATE_PROGRESS:
mDecorToolbar.initIndeterminateProgress();
break;
- case Window.FEATURE_ACTION_BAR_OVERLAY:
+ case AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR_OVERLAY:
setOverlayMode(true);
break;
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java b/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
index d97f8e7..32e6df2 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/ActivityChooserModel.java
@@ -972,7 +972,7 @@
}
try {
XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, null);
+ parser.setInput(fis, "UTF-8");
int type = XmlPullParser.START_DOCUMENT;
while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AdapterViewCompat.java b/v7/appcompat/src/android/support/v7/internal/widget/AdapterViewCompat.java
deleted file mode 100644
index bdce3c8..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/AdapterViewCompat.java
+++ /dev/null
@@ -1,1150 +0,0 @@
-package android.support.v7.internal.widget;
-
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.SoundEffectConstants;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.Adapter;
-import android.widget.AdapterView;
-import android.widget.ListView;
-
-
-/**
- * An AdapterView is a view whose children are determined by an {@link android.widget.Adapter}.
- *
- * <p>
- * See {@link ListView}, {@link android.widget.GridView}, {@link android.widget.Spinner} and
- * {@link android.widget.Gallery} for commonly used subclasses of AdapterView.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using AdapterView, read the
- * <a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a>
- * developer guide.</p></div>
- *
- * @hide
- */
-public abstract class AdapterViewCompat<T extends Adapter> extends ViewGroup {
-
- /**
- * The item view type returned by {@link Adapter#getItemViewType(int)} when
- * the adapter does not want the item's view recycled.
- */
- static final int ITEM_VIEW_TYPE_IGNORE = -1;
-
- /**
- * The item view type returned by {@link Adapter#getItemViewType(int)} when
- * the item is a header or footer.
- */
- static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2;
-
- /**
- * The position of the first child displayed
- */
- @ViewDebug.ExportedProperty(category = "scrolling")
- int mFirstPosition = 0;
-
- /**
- * The offset in pixels from the top of the AdapterView to the top
- * of the view to select during the next layout.
- */
- int mSpecificTop;
-
- /**
- * Position from which to start looking for mSyncRowId
- */
- int mSyncPosition;
-
- /**
- * Row id to look for when data has changed
- */
- long mSyncRowId = INVALID_ROW_ID;
-
- /**
- * Height of the view when mSyncPosition and mSyncRowId where set
- */
- long mSyncHeight;
-
- /**
- * True if we need to sync to mSyncRowId
- */
- boolean mNeedSync = false;
-
- /**
- * Indicates whether to sync based on the selection or position. Possible
- * values are {@link #SYNC_SELECTED_POSITION} or
- * {@link #SYNC_FIRST_POSITION}.
- */
- int mSyncMode;
-
- /**
- * Our height after the last layout
- */
- private int mLayoutHeight;
-
- /**
- * Sync based on the selected child
- */
- static final int SYNC_SELECTED_POSITION = 0;
-
- /**
- * Sync based on the first child displayed
- */
- static final int SYNC_FIRST_POSITION = 1;
-
- /**
- * Maximum amount of time to spend in {@link #findSyncPosition()}
- */
- static final int SYNC_MAX_DURATION_MILLIS = 100;
-
- /**
- * Indicates that this view is currently being laid out.
- */
- boolean mInLayout = false;
-
- /**
- * The listener that receives notifications when an item is selected.
- */
- OnItemSelectedListener mOnItemSelectedListener;
-
- /**
- * The listener that receives notifications when an item is clicked.
- */
- OnItemClickListener mOnItemClickListener;
-
- /**
- * The listener that receives notifications when an item is long clicked.
- */
- OnItemLongClickListener mOnItemLongClickListener;
-
- /**
- * True if the data has changed since the last layout
- */
- boolean mDataChanged;
-
- /**
- * The position within the adapter's data set of the item to select
- * during the next layout.
- */
- @ViewDebug.ExportedProperty(category = "list")
- int mNextSelectedPosition = INVALID_POSITION;
-
- /**
- * The item id of the item to select during the next layout.
- */
- long mNextSelectedRowId = INVALID_ROW_ID;
-
- /**
- * The position within the adapter's data set of the currently selected item.
- */
- @ViewDebug.ExportedProperty(category = "list")
- int mSelectedPosition = INVALID_POSITION;
-
- /**
- * The item id of the currently selected item.
- */
- long mSelectedRowId = INVALID_ROW_ID;
-
- /**
- * View to show if there are no items to show.
- */
- private View mEmptyView;
-
- /**
- * The number of items in the current adapter.
- */
- @ViewDebug.ExportedProperty(category = "list")
- int mItemCount;
-
- /**
- * The number of items in the adapter before a data changed event occurred.
- */
- int mOldItemCount;
-
- /**
- * Represents an invalid position. All valid positions are in the range 0 to 1 less than the
- * number of items in the current adapter.
- */
- public static final int INVALID_POSITION = -1;
-
- /**
- * Represents an empty or invalid row id
- */
- public static final long INVALID_ROW_ID = Long.MIN_VALUE;
-
- /**
- * The last selected position we used when notifying
- */
- int mOldSelectedPosition = INVALID_POSITION;
-
- /**
- * The id of the last selected position we used when notifying
- */
- long mOldSelectedRowId = INVALID_ROW_ID;
-
- /**
- * Indicates what focusable state is requested when calling setFocusable().
- * In addition to this, this view has other criteria for actually
- * determining the focusable state (such as whether its empty or the text
- * filter is shown).
- *
- * @see #setFocusable(boolean)
- * @see #checkFocus()
- */
- private boolean mDesiredFocusableState;
- private boolean mDesiredFocusableInTouchModeState;
-
- private SelectionNotifier mSelectionNotifier;
- /**
- * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
- * This is used to layout the children during a layout pass.
- */
- boolean mBlockLayoutRequests = false;
-
- AdapterViewCompat(Context context) {
- super(context);
- }
-
- AdapterViewCompat(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- AdapterViewCompat(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- /**
- * Interface definition for a callback to be invoked when an item in this
- * AdapterView has been clicked.
- */
- public interface OnItemClickListener {
-
- /**
- * Callback method to be invoked when an item in this AdapterView has
- * been clicked.
- * <p>
- * Implementers can call getItemAtPosition(position) if they need
- * to access the data associated with the selected item.
- *
- * @param parent The AdapterView where the click happened.
- * @param view The view within the AdapterView that was clicked (this
- * will be a view provided by the adapter)
- * @param position The position of the view in the adapter.
- * @param id The row id of the item that was clicked.
- */
- void onItemClick(AdapterViewCompat<?> parent, View view, int position, long id);
- }
-
- class OnItemClickListenerWrapper implements AdapterView.OnItemClickListener {
-
- private final OnItemClickListener mWrappedListener;
-
- public OnItemClickListenerWrapper(OnItemClickListener listener) {
- mWrappedListener = listener;
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mWrappedListener.onItemClick(AdapterViewCompat.this, view, position, id);
- }
- }
-
- /**
- * Register a callback to be invoked when an item in this AdapterView has
- * been clicked.
- *
- * @param listener The callback that will be invoked.
- */
- public void setOnItemClickListener(OnItemClickListener listener) {
- mOnItemClickListener = listener;
- }
-
- /**
- * @return The callback to be invoked with an item in this AdapterView has
- * been clicked, or null id no callback has been set.
- */
- public final OnItemClickListener getOnItemClickListener() {
- return mOnItemClickListener;
- }
-
- /**
- * Call the OnItemClickListener, if it is defined.
- *
- * @param view The view within the AdapterView that was clicked.
- * @param position The position of the view in the adapter.
- * @param id The row id of the item that was clicked.
- * @return True if there was an assigned OnItemClickListener that was
- * called, false otherwise is returned.
- */
- public boolean performItemClick(View view, int position, long id) {
- if (mOnItemClickListener != null) {
- playSoundEffect(SoundEffectConstants.CLICK);
- if (view != null) {
- view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
- }
- mOnItemClickListener.onItemClick(this, view, position, id);
- return true;
- }
-
- return false;
- }
-
- /**
- * Interface definition for a callback to be invoked when an item in this
- * view has been clicked and held.
- */
- public interface OnItemLongClickListener {
- /**
- * Callback method to be invoked when an item in this view has been
- * clicked and held.
- *
- * Implementers can call getItemAtPosition(position) if they need to access
- * the data associated with the selected item.
- *
- * @param parent The AbsListView where the click happened
- * @param view The view within the AbsListView that was clicked
- * @param position The position of the view in the list
- * @param id The row id of the item that was clicked
- *
- * @return true if the callback consumed the long click, false otherwise
- */
- boolean onItemLongClick(AdapterViewCompat<?> parent, View view, int position, long id);
- }
-
-
- /**
- * Register a callback to be invoked when an item in this AdapterView has
- * been clicked and held
- *
- * @param listener The callback that will run
- */
- public void setOnItemLongClickListener(OnItemLongClickListener listener) {
- if (!isLongClickable()) {
- setLongClickable(true);
- }
- mOnItemLongClickListener = listener;
- }
-
- /**
- * @return The callback to be invoked with an item in this AdapterView has
- * been clicked and held, or null id no callback as been set.
- */
- public final OnItemLongClickListener getOnItemLongClickListener() {
- return mOnItemLongClickListener;
- }
-
- /**
- * Interface definition for a callback to be invoked when
- * an item in this view has been selected.
- */
- public interface OnItemSelectedListener {
- /**
- * <p>Callback method to be invoked when an item in this view has been
- * selected. This callback is invoked only when the newly selected
- * position is different from the previously selected position or if
- * there was no selected item.</p>
- *
- * Impelmenters can call getItemAtPosition(position) if they need to access the
- * data associated with the selected item.
- *
- * @param parent The AdapterView where the selection happened
- * @param view The view within the AdapterView that was clicked
- * @param position The position of the view in the adapter
- * @param id The row id of the item that is selected
- */
- void onItemSelected(AdapterViewCompat<?> parent, View view, int position, long id);
-
- /**
- * Callback method to be invoked when the selection disappears from this
- * view. The selection can disappear for instance when touch is activated
- * or when the adapter becomes empty.
- *
- * @param parent The AdapterView that now contains no selected item.
- */
- void onNothingSelected(AdapterViewCompat<?> parent);
- }
-
-
- /**
- * Register a callback to be invoked when an item in this AdapterView has
- * been selected.
- *
- * @param listener The callback that will run
- */
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mOnItemSelectedListener = listener;
- }
-
- public final OnItemSelectedListener getOnItemSelectedListener() {
- return mOnItemSelectedListener;
- }
-
- /**
- * Extra menu information provided to the
- * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) }
- * callback when a context menu is brought up for this AdapterView.
- *
- */
- public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo {
-
- public AdapterContextMenuInfo(View targetView, int position, long id) {
- this.targetView = targetView;
- this.position = position;
- this.id = id;
- }
-
- /**
- * The child view for which the context menu is being displayed. This
- * will be one of the children of this AdapterView.
- */
- public View targetView;
-
- /**
- * The position in the adapter for which the context menu is being
- * displayed.
- */
- public int position;
-
- /**
- * The row id of the item for which the context menu is being displayed.
- */
- public long id;
- }
-
- /**
- * Returns the adapter currently associated with this widget.
- *
- * @return The adapter used to provide this view's content.
- */
- public abstract T getAdapter();
-
- /**
- * Sets the adapter that provides the data and the views to represent the data
- * in this widget.
- *
- * @param adapter The adapter to use to create this view's content.
- */
- public abstract void setAdapter(T adapter);
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child) {
- throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- * @param index Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child, int index) {
- throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- * @param params Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child, LayoutParams params) {
- throw new UnsupportedOperationException("addView(View, LayoutParams) "
- + "is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- * @param index Ignored.
- * @param params Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child, int index, LayoutParams params) {
- throw new UnsupportedOperationException("addView(View, int, LayoutParams) "
- + "is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void removeView(View child) {
- throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param index Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void removeViewAt(int index) {
- throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void removeAllViews() {
- throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView");
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mLayoutHeight = getHeight();
- }
-
- /**
- * Return the position of the currently selected item within the adapter's data set
- *
- * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected.
- */
- @ViewDebug.CapturedViewProperty
- public int getSelectedItemPosition() {
- return mNextSelectedPosition;
- }
-
- /**
- * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID}
- * if nothing is selected.
- */
- @ViewDebug.CapturedViewProperty
- public long getSelectedItemId() {
- return mNextSelectedRowId;
- }
-
- /**
- * @return The view corresponding to the currently selected item, or null
- * if nothing is selected
- */
- public abstract View getSelectedView();
-
- /**
- * @return The data corresponding to the currently selected item, or
- * null if there is nothing selected.
- */
- public Object getSelectedItem() {
- T adapter = getAdapter();
- int selection = getSelectedItemPosition();
- if (adapter != null && adapter.getCount() > 0 && selection >= 0) {
- return adapter.getItem(selection);
- } else {
- return null;
- }
- }
-
- /**
- * @return The number of items owned by the Adapter associated with this
- * AdapterView. (This is the number of data items, which may be
- * larger than the number of visible views.)
- */
- @ViewDebug.CapturedViewProperty
- public int getCount() {
- return mItemCount;
- }
-
- /**
- * Get the position within the adapter's data set for the view, where view is a an adapter item
- * or a descendant of an adapter item.
- *
- * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
- * AdapterView at the time of the call.
- * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
- * if the view does not correspond to a list item (or it is not currently visible).
- */
- public int getPositionForView(View view) {
- View listItem = view;
- try {
- View v;
- while (!(v = (View) listItem.getParent()).equals(this)) {
- listItem = v;
- }
- } catch (ClassCastException e) {
- // We made it up to the window without find this list view
- return INVALID_POSITION;
- }
-
- // Search the children for the list item
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- if (getChildAt(i).equals(listItem)) {
- return mFirstPosition + i;
- }
- }
-
- // Child not found!
- return INVALID_POSITION;
- }
-
- /**
- * Returns the position within the adapter's data set for the first item
- * displayed on screen.
- *
- * @return The position within the adapter's data set
- */
- public int getFirstVisiblePosition() {
- return mFirstPosition;
- }
-
- /**
- * Returns the position within the adapter's data set for the last item
- * displayed on screen.
- *
- * @return The position within the adapter's data set
- */
- public int getLastVisiblePosition() {
- return mFirstPosition + getChildCount() - 1;
- }
-
- /**
- * Sets the currently selected item. To support accessibility subclasses that
- * override this method must invoke the overriden super method first.
- *
- * @param position Index (starting at 0) of the data item to be selected.
- */
- public abstract void setSelection(int position);
-
- /**
- * Sets the view to show if the adapter is empty
- */
- public void setEmptyView(View emptyView) {
- mEmptyView = emptyView;
-
- final T adapter = getAdapter();
- final boolean empty = ((adapter == null) || adapter.isEmpty());
- updateEmptyStatus(empty);
- }
-
- /**
- * When the current adapter is empty, the AdapterView can display a special view
- * call the empty view. The empty view is used to provide feedback to the user
- * that no data is available in this AdapterView.
- *
- * @return The view to show if the adapter is empty.
- */
- public View getEmptyView() {
- return mEmptyView;
- }
-
- /**
- * Indicates whether this view is in filter mode. Filter mode can for instance
- * be enabled by a user when typing on the keyboard.
- *
- * @return True if the view is in filter mode, false otherwise.
- */
- boolean isInFilterMode() {
- return false;
- }
-
- @Override
- public void setFocusable(boolean focusable) {
- final T adapter = getAdapter();
- final boolean empty = adapter == null || adapter.getCount() == 0;
-
- mDesiredFocusableState = focusable;
- if (!focusable) {
- mDesiredFocusableInTouchModeState = false;
- }
-
- super.setFocusable(focusable && (!empty || isInFilterMode()));
- }
-
- @Override
- public void setFocusableInTouchMode(boolean focusable) {
- final T adapter = getAdapter();
- final boolean empty = adapter == null || adapter.getCount() == 0;
-
- mDesiredFocusableInTouchModeState = focusable;
- if (focusable) {
- mDesiredFocusableState = true;
- }
-
- super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode()));
- }
-
- void checkFocus() {
- final T adapter = getAdapter();
- final boolean empty = adapter == null || adapter.getCount() == 0;
- final boolean focusable = !empty || isInFilterMode();
- // The order in which we set focusable in touch mode/focusable may matter
- // for the client, see View.setFocusableInTouchMode() comments for more
- // details
- super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState);
- super.setFocusable(focusable && mDesiredFocusableState);
- if (mEmptyView != null) {
- updateEmptyStatus((adapter == null) || adapter.isEmpty());
- }
- }
-
- /**
- * Update the status of the list based on the empty parameter. If empty is true and
- * we have an empty view, display it. In all the other cases, make sure that the listview
- * is VISIBLE and that the empty view is GONE (if it's not null).
- */
- private void updateEmptyStatus(boolean empty) {
- if (isInFilterMode()) {
- empty = false;
- }
-
- if (empty) {
- if (mEmptyView != null) {
- mEmptyView.setVisibility(View.VISIBLE);
- setVisibility(View.GONE);
- } else {
- // If the caller just removed our empty view, make sure the list view is visible
- setVisibility(View.VISIBLE);
- }
-
- // We are now GONE, so pending layouts will not be dispatched.
- // Force one here to make sure that the state of the list matches
- // the state of the adapter.
- if (mDataChanged) {
- this.onLayout(false, getLeft(), getTop(), getRight(), getBottom());
- }
- } else {
- if (mEmptyView != null) mEmptyView.setVisibility(View.GONE);
- setVisibility(View.VISIBLE);
- }
- }
-
- /**
- * Gets the data associated with the specified position in the list.
- *
- * @param position Which data to get
- * @return The data associated with the specified position in the list
- */
- public Object getItemAtPosition(int position) {
- T adapter = getAdapter();
- return (adapter == null || position < 0) ? null : adapter.getItem(position);
- }
-
- public long getItemIdAtPosition(int position) {
- T adapter = getAdapter();
- return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
- }
-
- @Override
- public void setOnClickListener(OnClickListener l) {
- throw new RuntimeException("Don't call setOnClickListener for an AdapterView. "
- + "You probably want setOnItemClickListener instead");
- }
-
- /**
- * Override to prevent freezing of any views created by the adapter.
- */
- @Override
- protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
- dispatchFreezeSelfOnly(container);
- }
-
- /**
- * Override to prevent thawing of any views created by the adapter.
- */
- @Override
- protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
- dispatchThawSelfOnly(container);
- }
-
- class AdapterDataSetObserver extends DataSetObserver {
-
- private Parcelable mInstanceState = null;
-
- @Override
- public void onChanged() {
- mDataChanged = true;
- mOldItemCount = mItemCount;
- mItemCount = getAdapter().getCount();
-
- // Detect the case where a cursor that was previously invalidated has
- // been repopulated with new data.
- if (AdapterViewCompat.this.getAdapter().hasStableIds() && mInstanceState != null
- && mOldItemCount == 0 && mItemCount > 0) {
- AdapterViewCompat.this.onRestoreInstanceState(mInstanceState);
- mInstanceState = null;
- } else {
- rememberSyncState();
- }
- checkFocus();
- requestLayout();
- }
-
- @Override
- public void onInvalidated() {
- mDataChanged = true;
-
- if (AdapterViewCompat.this.getAdapter().hasStableIds()) {
- // Remember the current state for the case where our hosting activity is being
- // stopped and later restarted
- mInstanceState = AdapterViewCompat.this.onSaveInstanceState();
- }
-
- // Data is invalid so we should reset our state
- mOldItemCount = mItemCount;
- mItemCount = 0;
- mSelectedPosition = INVALID_POSITION;
- mSelectedRowId = INVALID_ROW_ID;
- mNextSelectedPosition = INVALID_POSITION;
- mNextSelectedRowId = INVALID_ROW_ID;
- mNeedSync = false;
-
- checkFocus();
- requestLayout();
- }
-
- public void clearSavedState() {
- mInstanceState = null;
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- removeCallbacks(mSelectionNotifier);
- }
-
- private class SelectionNotifier implements Runnable {
- public void run() {
- if (mDataChanged) {
- // Data has changed between when this SelectionNotifier
- // was posted and now. We need to wait until the AdapterView
- // has been synched to the new data.
- if (getAdapter() != null) {
- post(this);
- }
- } else {
- fireOnSelected();
- }
- }
- }
-
- void selectionChanged() {
- if (mOnItemSelectedListener != null) {
- if (mInLayout || mBlockLayoutRequests) {
- // If we are in a layout traversal, defer notification
- // by posting. This ensures that the view tree is
- // in a consistent state and is able to accomodate
- // new layout or invalidate requests.
- if (mSelectionNotifier == null) {
- mSelectionNotifier = new SelectionNotifier();
- }
- post(mSelectionNotifier);
- } else {
- fireOnSelected();
- }
- }
-
- // we fire selection events here not in View
- if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
- }
-
- private void fireOnSelected() {
- if (mOnItemSelectedListener == null)
- return;
-
- int selection = this.getSelectedItemPosition();
- if (selection >= 0) {
- View v = getSelectedView();
- mOnItemSelectedListener.onItemSelected(this, v, selection,
- getAdapter().getItemId(selection));
- } else {
- mOnItemSelectedListener.onNothingSelected(this);
- }
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- View selectedView = getSelectedView();
- if (selectedView != null && selectedView.getVisibility() == VISIBLE
- && selectedView.dispatchPopulateAccessibilityEvent(event)) {
- return true;
- }
- return false;
- }
-
- @Override
- protected boolean canAnimate() {
- return super.canAnimate() && mItemCount > 0;
- }
-
- void handleDataChanged() {
- final int count = mItemCount;
- boolean found = false;
-
- if (count > 0) {
-
- int newPos;
-
- // Find the row we are supposed to sync to
- if (mNeedSync) {
- // Update this first, since setNextSelectedPositionInt inspects
- // it
- mNeedSync = false;
-
- // See if we can find a position in the new data with the same
- // id as the old selection
- newPos = findSyncPosition();
- if (newPos >= 0) {
- // Verify that new selection is selectable
- int selectablePos = lookForSelectablePosition(newPos, true);
- if (selectablePos == newPos) {
- // Same row id is selected
- setNextSelectedPositionInt(newPos);
- found = true;
- }
- }
- }
- if (!found) {
- // Try to use the same position if we can't find matching data
- newPos = getSelectedItemPosition();
-
- // Pin position to the available range
- if (newPos >= count) {
- newPos = count - 1;
- }
- if (newPos < 0) {
- newPos = 0;
- }
-
- // Make sure we select something selectable -- first look down
- int selectablePos = lookForSelectablePosition(newPos, true);
- if (selectablePos < 0) {
- // Looking down didn't work -- try looking up
- selectablePos = lookForSelectablePosition(newPos, false);
- }
- if (selectablePos >= 0) {
- setNextSelectedPositionInt(selectablePos);
- checkSelectionChanged();
- found = true;
- }
- }
- }
- if (!found) {
- // Nothing is selected
- mSelectedPosition = INVALID_POSITION;
- mSelectedRowId = INVALID_ROW_ID;
- mNextSelectedPosition = INVALID_POSITION;
- mNextSelectedRowId = INVALID_ROW_ID;
- mNeedSync = false;
- checkSelectionChanged();
- }
- }
-
- void checkSelectionChanged() {
- if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
- selectionChanged();
- mOldSelectedPosition = mSelectedPosition;
- mOldSelectedRowId = mSelectedRowId;
- }
- }
-
- /**
- * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition
- * and then alternates between moving up and moving down until 1) we find the right position, or
- * 2) we run out of time, or 3) we have looked at every position
- *
- * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't
- * be found
- */
- int findSyncPosition() {
- int count = mItemCount;
-
- if (count == 0) {
- return INVALID_POSITION;
- }
-
- long idToMatch = mSyncRowId;
- int seed = mSyncPosition;
-
- // If there isn't a selection don't hunt for it
- if (idToMatch == INVALID_ROW_ID) {
- return INVALID_POSITION;
- }
-
- // Pin seed to reasonable values
- seed = Math.max(0, seed);
- seed = Math.min(count - 1, seed);
-
- long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS;
-
- long rowId;
-
- // first position scanned so far
- int first = seed;
-
- // last position scanned so far
- int last = seed;
-
- // True if we should move down on the next iteration
- boolean next = false;
-
- // True when we have looked at the first item in the data
- boolean hitFirst;
-
- // True when we have looked at the last item in the data
- boolean hitLast;
-
- // Get the item ID locally (instead of getItemIdAtPosition), so
- // we need the adapter
- T adapter = getAdapter();
- if (adapter == null) {
- return INVALID_POSITION;
- }
-
- while (SystemClock.uptimeMillis() <= endTime) {
- rowId = adapter.getItemId(seed);
- if (rowId == idToMatch) {
- // Found it!
- return seed;
- }
-
- hitLast = last == count - 1;
- hitFirst = first == 0;
-
- if (hitLast && hitFirst) {
- // Looked at everything
- break;
- }
-
- if (hitFirst || (next && !hitLast)) {
- // Either we hit the top, or we are trying to move down
- last++;
- seed = last;
- // Try going up next time
- next = false;
- } else if (hitLast || (!next && !hitFirst)) {
- // Either we hit the bottom, or we are trying to move up
- first--;
- seed = first;
- // Try going down next time
- next = true;
- }
-
- }
-
- return INVALID_POSITION;
- }
-
- /**
- * Find a position that can be selected (i.e., is not a separator).
- *
- * @param position The starting position to look at.
- * @param lookDown Whether to look down for other positions.
- * @return The next selectable position starting at position and then searching either up or
- * down. Returns {@link #INVALID_POSITION} if nothing can be found.
- */
- int lookForSelectablePosition(int position, boolean lookDown) {
- return position;
- }
-
- /**
- * Utility to keep mSelectedPosition and mSelectedRowId in sync
- * @param position Our current position
- */
- void setSelectedPositionInt(int position) {
- mSelectedPosition = position;
- mSelectedRowId = getItemIdAtPosition(position);
- }
-
- /**
- * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync
- * @param position Intended value for mSelectedPosition the next time we go
- * through layout
- */
- void setNextSelectedPositionInt(int position) {
- mNextSelectedPosition = position;
- mNextSelectedRowId = getItemIdAtPosition(position);
- // If we are trying to sync to the selection, update that too
- if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) {
- mSyncPosition = position;
- mSyncRowId = mNextSelectedRowId;
- }
- }
-
- /**
- * Remember enough information to restore the screen state when the data has
- * changed.
- *
- */
- void rememberSyncState() {
- if (getChildCount() > 0) {
- mNeedSync = true;
- mSyncHeight = mLayoutHeight;
- if (mSelectedPosition >= 0) {
- // Sync the selection state
- View v = getChildAt(mSelectedPosition - mFirstPosition);
- mSyncRowId = mNextSelectedRowId;
- mSyncPosition = mNextSelectedPosition;
- if (v != null) {
- mSpecificTop = v.getTop();
- }
- mSyncMode = SYNC_SELECTED_POSITION;
- } else {
- // Sync the based on the offset of the first view
- View v = getChildAt(0);
- T adapter = getAdapter();
- if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) {
- mSyncRowId = adapter.getItemId(mFirstPosition);
- } else {
- mSyncRowId = NO_ID;
- }
- mSyncPosition = mFirstPosition;
- if (v != null) {
- mSpecificTop = v.getTop();
- }
- mSyncMode = SYNC_FIRST_POSITION;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java b/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
index 511a332..d71d606 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/AppCompatPopupWindow.java
@@ -19,6 +19,7 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
+import android.support.v4.widget.PopupWindowCompat;
import android.support.v7.appcompat.R;
import android.util.AttributeSet;
import android.util.Log;
@@ -35,15 +36,18 @@
public class AppCompatPopupWindow extends PopupWindow {
private static final String TAG = "AppCompatPopupWindow";
+ private static final boolean COMPAT_OVERLAP_ANCHOR = Build.VERSION.SDK_INT < 21;
- private final boolean mOverlapAnchor;
+ private boolean mOverlapAnchor;
public AppCompatPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.PopupWindow, defStyleAttr, 0);
- mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
+ if (a.hasValue(R.styleable.PopupWindow_overlapAnchor)) {
+ setSupportOverlapAnchor(a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false));
+ }
// We re-set this for tinting purposes
setBackgroundDrawable(a.getDrawable(R.styleable.PopupWindow_android_popupBackground));
a.recycle();
@@ -57,7 +61,7 @@
@Override
public void showAsDropDown(View anchor, int xoff, int yoff) {
- if (Build.VERSION.SDK_INT < 21 && mOverlapAnchor) {
+ if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
// If we're pre-L, emulate overlapAnchor by modifying the yOff
yoff -= anchor.getHeight();
}
@@ -67,7 +71,7 @@
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
- if (Build.VERSION.SDK_INT < 21 && mOverlapAnchor) {
+ if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
// If we're pre-L, emulate overlapAnchor by modifying the yOff
yoff -= anchor.getHeight();
}
@@ -76,7 +80,7 @@
@Override
public void update(View anchor, int xoff, int yoff, int width, int height) {
- if (Build.VERSION.SDK_INT < 21 && mOverlapAnchor) {
+ if (COMPAT_OVERLAP_ANCHOR && mOverlapAnchor) {
// If we're pre-L, emulate overlapAnchor by modifying the yOff
yoff -= anchor.getHeight();
}
@@ -117,4 +121,26 @@
}
}
+ /**
+ * @hide
+ */
+ public void setSupportOverlapAnchor(boolean overlapAnchor) {
+ if (COMPAT_OVERLAP_ANCHOR) {
+ mOverlapAnchor = overlapAnchor;
+ } else {
+ PopupWindowCompat.setOverlapAnchor(this, overlapAnchor);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean getSupportOverlapAnchor() {
+ if (COMPAT_OVERLAP_ANCHOR) {
+ return mOverlapAnchor;
+ } else {
+ return PopupWindowCompat.getOverlapAnchor(this);
+ }
+ }
+
}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java b/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
index c601e64..52d53b3 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/DecorToolbar.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
+import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuPresenter;
import android.util.SparseArray;
@@ -27,6 +28,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.widget.AdapterView;
import android.widget.SpinnerAdapter;
/**
@@ -39,7 +41,6 @@
public interface DecorToolbar {
ViewGroup getViewGroup();
Context getContext();
- boolean isSplit();
boolean hasExpandedActionView();
void collapseActionView();
void setWindowCallback(Window.Callback cb);
@@ -50,10 +51,6 @@
void setSubtitle(CharSequence subtitle);
void initProgress();
void initIndeterminateProgress();
- boolean canSplit();
- void setSplitView(ViewGroup splitView);
- void setSplitToolbar(boolean split);
- void setSplitWhenNarrow(boolean splitWhenNarrow);
boolean hasIcon();
boolean hasLogo();
void setIcon(int resId);
@@ -78,13 +75,14 @@
void setHomeButtonEnabled(boolean enable);
int getNavigationMode();
void setNavigationMode(int mode);
- void setDropdownParams(SpinnerAdapter adapter, AdapterViewCompat.OnItemSelectedListener listener);
+ void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener listener);
void setDropdownSelectedPosition(int position);
int getDropdownSelectedPosition();
int getDropdownItemCount();
void setCustomView(View view);
View getCustomView();
void animateToVisibility(int visibility);
+ ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration);
void setNavigationIcon(Drawable icon);
void setNavigationIcon(int resId);
void setNavigationContentDescription(CharSequence description);
@@ -100,5 +98,4 @@
void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
MenuBuilder.Callback menuBuilderCallback);
Menu getMenu();
- int getPopupTheme();
}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java b/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
index 7c5c2cb..0d27d32 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/ScrollingTabContainerView.java
@@ -26,6 +26,7 @@
import android.support.v7.app.ActionBar;
import android.support.v7.appcompat.R;
import android.support.v7.internal.view.ActionBarPolicy;
+import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.AppCompatTextView;
import android.support.v7.widget.LinearLayoutCompat;
import android.text.TextUtils;
@@ -38,10 +39,12 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
@@ -52,14 +55,14 @@
* @hide
*/
public class ScrollingTabContainerView extends HorizontalScrollView
- implements AdapterViewCompat.OnItemClickListener {
+ implements AdapterView.OnItemSelectedListener {
private static final String TAG = "ScrollingTabContainerView";
Runnable mTabSelector;
private TabClickListener mTabClickListener;
private LinearLayoutCompat mTabLayout;
- private SpinnerCompat mTabSpinner;
+ private Spinner mTabSpinner;
private boolean mAllowCollapse;
int mMaxTabWidth;
@@ -206,12 +209,13 @@
return tabLayout;
}
- private SpinnerCompat createSpinner() {
- final SpinnerCompat spinner = new SpinnerCompat(getContext(), null,
+ private Spinner createSpinner() {
+ final Spinner spinner = new AppCompatSpinner(getContext(), null,
R.attr.actionDropDownStyle);
spinner.setLayoutParams(new LinearLayoutCompat.LayoutParams(
- LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.MATCH_PARENT));
- spinner.setOnItemClickListenerInt(this);
+ LinearLayoutCompat.LayoutParams.WRAP_CONTENT,
+ LinearLayoutCompat.LayoutParams.MATCH_PARENT));
+ spinner.setOnItemSelectedListener(this);
return spinner;
}
@@ -362,11 +366,16 @@
}
@Override
- public void onItemClick(AdapterViewCompat<?> parent, View view, int position, long id) {
+ public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
TabView tabView = (TabView) view;
tabView.getTab().select();
}
+ @Override
+ public void onNothingSelected(AdapterView<?> adapterView) {
+ // no-op
+ }
+
private class TabView extends LinearLayoutCompat implements OnLongClickListener {
private final int[] BG_ATTRS = {
android.R.attr.background
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/SpinnerCompat.java b/v7/appcompat/src/android/support/v7/internal/widget/SpinnerCompat.java
deleted file mode 100644
index b2b8af2..0000000
--- a/v7/appcompat/src/android/support/v7/internal/widget/SpinnerCompat.java
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.internal.widget;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.database.DataSetObserver;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.appcompat.R;
-import android.support.v7.widget.ListPopupWindow;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.AdapterView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.PopupWindow;
-import android.widget.SpinnerAdapter;
-
-
-/**
- * A view that displays one child at a time and lets the user pick among them. The items in the
- * Spinner come from the {@link android.widget.Adapter} associated with this view.
- *
- * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner
- * tutorial</a>.</p>
- */
-class SpinnerCompat extends AbsSpinnerCompat implements DialogInterface.OnClickListener {
- private static final String TAG = "Spinner";
-
- // Only measure this many items to get a decent max width.
- private static final int MAX_ITEMS_MEASURED = 15;
-
- /**
- * Use a dialog window for selecting spinner options.
- */
- public static final int MODE_DIALOG = 0;
-
- /**
- * Use a dropdown anchored to the Spinner for selecting spinner options.
- */
- public static final int MODE_DROPDOWN = 1;
-
- /**
- * Use the theme-supplied value to select the dropdown mode.
- */
- private static final int MODE_THEME = -1;
-
- /**
- * Forwarding listener used to implement drag-to-open.
- */
- private ListPopupWindow.ForwardingListener mForwardingListener;
-
- private SpinnerPopup mPopup;
-
- private DropDownAdapter mTempAdapter;
-
- int mDropDownWidth;
-
- private int mGravity;
-
- private boolean mDisableChildrenWhenDisabled;
-
- private Rect mTempRect = new Rect();
-
- private final TintManager mTintManager;
-
- /**
- * Construct a new spinner with the given context's theme.
- *
- * @param context The Context the view is running in, through which it can access the current
- * theme, resources, etc.
- */
- SpinnerCompat(Context context) {
- this(context, null);
- }
-
- /**
- * Construct a new spinner with the given context's theme and the supplied mode of displaying
- * choices. <code>mode</code> may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}.
- *
- * @param context The Context the view is running in, through which it can access the current
- * theme, resources, etc.
- * @param mode Constant describing how the user will select choices from the spinner.
- * @see #MODE_DIALOG
- * @see #MODE_DROPDOWN
- */
- SpinnerCompat(Context context, int mode) {
- this(context, null, R.attr.spinnerStyle, mode);
- }
-
- /**
- * Construct a new spinner with the given context's theme and the supplied attribute set.
- *
- * @param context The Context the view is running in, through which it can access the current
- * theme, resources, etc.
- * @param attrs The attributes of the XML tag that is inflating the view.
- */
- SpinnerCompat(Context context, AttributeSet attrs) {
- this(context, attrs, R.attr.spinnerStyle);
- }
-
- /**
- * Construct a new spinner with the given context's theme, the supplied attribute set, and
- * default style.
- *
- * @param context The Context the view is running in, through which it can access the current
- * theme, resources, etc.
- * @param attrs The attributes of the XML tag that is inflating the view.
- * @param defStyle The default style to apply to this view. If 0, no style will be applied
- * (beyond what is included in the theme). This may either be an attribute
- * resource, whose value will be retrieved from the current theme, or an
- * explicit style resource.
- */
- SpinnerCompat(Context context, AttributeSet attrs, int defStyle) {
- this(context, attrs, defStyle, MODE_THEME);
- }
-
- /**
- * Construct a new spinner with the given context's theme, the supplied attribute set, and
- * default style. <code>mode</code> may be one of {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}
- * and determines how the user will select choices from the spinner.
- *
- * @param context The Context the view is running in, through which it can access the current
- * theme, resources, etc.
- * @param attrs The attributes of the XML tag that is inflating the view.
- * @param defStyle The default style to apply to this view. If 0, no style will be applied
- * (beyond what is included in the theme). This may either be an attribute
- * resource, whose value will be retrieved from the current theme, or an
- * explicit style resource.
- * @param mode Constant describing how the user will select choices from the spinner.
- * @see #MODE_DIALOG
- * @see #MODE_DROPDOWN
- */
- SpinnerCompat(Context context, AttributeSet attrs, int defStyle, int mode) {
- super(context, attrs, defStyle);
-
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
- R.styleable.Spinner, defStyle, 0);
-
- // Need to reset this for tinting purposes
- if (a.hasValue(R.styleable.Spinner_android_background)) {
- setBackgroundDrawable(a.getDrawable(R.styleable.Spinner_android_background));
- }
-
- if (mode == MODE_THEME) {
- mode = a.getInt(R.styleable.Spinner_spinnerMode, MODE_DIALOG);
- }
-
- switch (mode) {
- case MODE_DIALOG: {
- mPopup = new DialogPopup();
- break;
- }
-
- case MODE_DROPDOWN: {
- final DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
-
- mDropDownWidth = a.getLayoutDimension(R.styleable.Spinner_android_dropDownWidth,
- ViewGroup.LayoutParams.WRAP_CONTENT);
-
- popup.setBackgroundDrawable(
- a.getDrawable(R.styleable.Spinner_android_popupBackground));
-
- mPopup = popup;
- mForwardingListener = new ListPopupWindow.ForwardingListener(this) {
- @Override
- public ListPopupWindow getPopup() {
- return popup;
- }
-
- @Override
- public boolean onForwardingStarted() {
- if (!mPopup.isShowing()) {
- mPopup.show();
- }
- return true;
- }
- };
- break;
- }
- }
-
- mGravity = a.getInt(R.styleable.Spinner_android_gravity, Gravity.CENTER);
-
- mPopup.setPromptText(a.getString(R.styleable.Spinner_prompt));
-
- mDisableChildrenWhenDisabled = a.getBoolean(
- R.styleable.Spinner_disableChildrenWhenDisabled, false);
-
- a.recycle();
-
- // Base constructor can call setAdapter before we initialize mPopup.
- // Finish setting things up if this happened.
- if (mTempAdapter != null) {
- mPopup.setAdapter(mTempAdapter);
- mTempAdapter = null;
- }
-
- // Keep the TintManager in case we need it later
- mTintManager = a.getTintManager();
- }
-
- /**
- * Set the background drawable for the spinner's popup window of choices. Only valid in {@link
- * #MODE_DROPDOWN}; this method is a no-op in other modes.
- *
- * @param background Background drawable
- */
- public void setPopupBackgroundDrawable(Drawable background) {
- if (!(mPopup instanceof DropdownPopup)) {
- Log.e(TAG, "setPopupBackgroundDrawable: incompatible spinner mode; ignoring...");
- return;
- }
- ((DropdownPopup) mPopup).setBackgroundDrawable(background);
- }
-
- /**
- * Set the background drawable for the spinner's popup window of choices. Only valid in {@link
- * #MODE_DROPDOWN}; this method is a no-op in other modes.
- *
- * @param resId Resource ID of a background drawable
- */
- public void setPopupBackgroundResource(int resId) {
- setPopupBackgroundDrawable(mTintManager.getDrawable(resId));
- }
-
- /**
- * Get the background drawable for the spinner's popup window of choices. Only valid in {@link
- * #MODE_DROPDOWN}; other modes will return null.
- *
- * @return background Background drawable
- */
- public Drawable getPopupBackground() {
- return mPopup.getBackground();
- }
-
- /**
- * Set a vertical offset in pixels for the spinner's popup window of choices. Only valid in
- * {@link #MODE_DROPDOWN}; this method is a no-op in other modes.
- *
- * @param pixels Vertical offset in pixels
- */
- public void setDropDownVerticalOffset(int pixels) {
- mPopup.setVerticalOffset(pixels);
- }
-
- /**
- * Get the configured vertical offset in pixels for the spinner's popup window of choices. Only
- * valid in {@link #MODE_DROPDOWN}; other modes will return 0.
- *
- * @return Vertical offset in pixels
- */
- public int getDropDownVerticalOffset() {
- return mPopup.getVerticalOffset();
- }
-
- /**
- * Set a horizontal offset in pixels for the spinner's popup window of choices. Only valid in
- * {@link #MODE_DROPDOWN}; this method is a no-op in other modes.
- *
- * @param pixels Horizontal offset in pixels
- */
- public void setDropDownHorizontalOffset(int pixels) {
- mPopup.setHorizontalOffset(pixels);
- }
-
- /**
- * Get the configured horizontal offset in pixels for the spinner's popup window of choices.
- * Only valid in {@link #MODE_DROPDOWN}; other modes will return 0.
- *
- * @return Horizontal offset in pixels
- */
- public int getDropDownHorizontalOffset() {
- return mPopup.getHorizontalOffset();
- }
-
- /**
- * Set the width of the spinner's popup window of choices in pixels. This value may also be set
- * to {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} to match the width of the Spinner
- * itself, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} to wrap to the measured
- * size of contained dropdown list items.
- *
- * <p>Only valid in {@link #MODE_DROPDOWN}; this method is a no-op in other modes.</p>
- *
- * @param pixels Width in pixels, WRAP_CONTENT, or MATCH_PARENT
- */
- public void setDropDownWidth(int pixels) {
- if (!(mPopup instanceof DropdownPopup)) {
- Log.e(TAG, "Cannot set dropdown width for MODE_DIALOG, ignoring");
- return;
- }
- mDropDownWidth = pixels;
- }
-
- /**
- * Get the configured width of the spinner's popup window of choices in pixels. The returned
- * value may also be {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} meaning the popup
- * window will match the width of the Spinner itself, or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
- * to wrap to the measured size of contained dropdown list items.
- *
- * @return Width in pixels, WRAP_CONTENT, or MATCH_PARENT
- */
- public int getDropDownWidth() {
- return mDropDownWidth;
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- if (mDisableChildrenWhenDisabled) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- getChildAt(i).setEnabled(enabled);
- }
- }
- }
-
- /**
- * Describes how the selected item view is positioned. Currently only the horizontal component
- * is used. The default is determined by the current theme.
- *
- * @param gravity See {@link android.view.Gravity}
- */
- public void setGravity(int gravity) {
- if (mGravity != gravity) {
- if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
- gravity |= GravityCompat.START;
- }
- mGravity = gravity;
- requestLayout();
- }
- }
-
- @Override
- public void setAdapter(SpinnerAdapter adapter) {
- super.setAdapter(adapter);
-
- mRecycler.clear();
-
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP
- && adapter != null && adapter.getViewTypeCount() != 1) {
- throw new IllegalArgumentException("Spinner adapter view type count must be 1");
- }
- if (mPopup != null) {
- mPopup.setAdapter(new DropDownAdapter(adapter));
- } else {
- mTempAdapter = new DropDownAdapter(adapter);
- }
- }
-
- @Override
- public int getBaseline() {
- View child = null;
-
- if (getChildCount() > 0) {
- child = getChildAt(0);
- } else if (mAdapter != null && mAdapter.getCount() > 0) {
- child = makeView(0, false);
- mRecycler.put(0, child);
- }
-
- if (child != null) {
- final int childBaseline = child.getBaseline();
- return childBaseline >= 0 ? child.getTop() + childBaseline : -1;
- } else {
- return -1;
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- if (mPopup != null && mPopup.isShowing()) {
- mPopup.dismiss();
- }
- }
-
- /**
- * <p>A spinner does not support item click events. Calling this method will raise an
- * exception.</p>
- *
- * @param l this listener will be ignored
- */
- @Override
- public void setOnItemClickListener(OnItemClickListener l) {
- throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
- }
-
- void setOnItemClickListenerInt(OnItemClickListener l) {
- super.setOnItemClickListener(l);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mForwardingListener != null && mForwardingListener.onTouch(this, event)) {
- return true;
- }
-
- return super.onTouchEvent(event);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
- final int measuredWidth = getMeasuredWidth();
- setMeasuredDimension(Math.min(Math.max(measuredWidth,
- measureContentWidth(getAdapter(), getBackground())),
- MeasureSpec.getSize(widthMeasureSpec)),
- getMeasuredHeight());
- }
- }
-
- /**
- * @see android.view.View#onLayout(boolean, int, int, int, int)
- *
- * Creates and positions all views
- */
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mInLayout = true;
- layout(0, false);
- mInLayout = false;
- }
-
- /**
- * Creates and positions all views for this Spinner.
- *
- * @param delta Change in the selected position. +1 means selection is moving to the right, so
- * views are scrolling to the left. -1 means selection is moving to the left.
- */
- @Override
- void layout(int delta, boolean animate) {
- int childrenLeft = mSpinnerPadding.left;
- int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right;
-
- if (mDataChanged) {
- handleDataChanged();
- }
-
- // Handle the empty set by removing all views
- if (mItemCount == 0) {
- resetList();
- return;
- }
-
- if (mNextSelectedPosition >= 0) {
- setSelectedPositionInt(mNextSelectedPosition);
- }
-
- recycleAllViews();
-
- // Clear out old views
- removeAllViewsInLayout();
-
- // Make selected view and position it
- mFirstPosition = mSelectedPosition;
- if (mAdapter != null) {
- View sel = makeView(mSelectedPosition, true);
- int width = sel.getMeasuredWidth();
- int selectedOffset = childrenLeft;
- final int layoutDirection = ViewCompat.getLayoutDirection(this);
- final int absoluteGravity = GravityCompat.getAbsoluteGravity(mGravity, layoutDirection);
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
- break;
- case Gravity.RIGHT:
- selectedOffset = childrenLeft + childrenWidth - width;
- break;
- }
- sel.offsetLeftAndRight(selectedOffset);
- }
-
- // Flush any cached views that did not get reused above
- mRecycler.clear();
-
- invalidate();
-
- checkSelectionChanged();
-
- mDataChanged = false;
- mNeedSync = false;
- setNextSelectedPositionInt(mSelectedPosition);
- }
-
- /**
- * Obtain a view, either by pulling an existing view from the recycler or by getting a new one
- * from the adapter. If we are animating, make sure there is enough information in the view's
- * layout parameters to animate from the old to new positions.
- *
- * @param position Position in the spinner for the view to obtain
- * @param addChild true to add the child to the spinner, false to obtain and configure only.
- * @return A view for the given position
- */
- private View makeView(int position, boolean addChild) {
-
- View child;
-
- if (!mDataChanged) {
- child = mRecycler.get(position);
- if (child != null) {
- // Position the view
- setUpChild(child, addChild);
-
- return child;
- }
- }
-
- // Nothing found in the recycler -- ask the adapter for a view
- child = mAdapter.getView(position, null, this);
-
- // Position the view
- setUpChild(child, addChild);
-
- return child;
- }
-
- /**
- * Helper for makeAndAddView to set the position of a view and fill out its layout paramters.
- *
- * @param child The view to position
- * @param addChild true if the child should be added to the Spinner during setup
- */
- private void setUpChild(View child, boolean addChild) {
-
- // Respect layout params that are already in the view. Otherwise
- // make some up...
- ViewGroup.LayoutParams lp = child.getLayoutParams();
- if (lp == null) {
- lp = generateDefaultLayoutParams();
- }
-
- if (addChild) {
- addViewInLayout(child, 0, lp);
- }
-
- child.setSelected(hasFocus());
- if (mDisableChildrenWhenDisabled) {
- child.setEnabled(isEnabled());
- }
-
- // Get measure specs
- int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
- mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
- int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
- mSpinnerPadding.left + mSpinnerPadding.right, lp.width);
-
- // Measure child
- child.measure(childWidthSpec, childHeightSpec);
-
- int childLeft;
- int childRight;
-
- // Position vertically based on gravity setting
- int childTop = mSpinnerPadding.top
- + ((getMeasuredHeight() - mSpinnerPadding.bottom -
- mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
- int childBottom = childTop + child.getMeasuredHeight();
-
- int width = child.getMeasuredWidth();
- childLeft = 0;
- childRight = childLeft + width;
-
- child.layout(childLeft, childTop, childRight, childBottom);
- }
-
- @Override
- public boolean performClick() {
- boolean handled = super.performClick();
-
- if (!handled) {
- handled = true;
-
- if (!mPopup.isShowing()) {
- mPopup.show();
- }
- }
-
- return handled;
- }
-
- public void onClick(DialogInterface dialog, int which) {
- setSelection(which);
- dialog.dismiss();
- }
-
- /**
- * Sets the prompt to display when the dialog is shown.
- * @param prompt the prompt to set
- */
- public void setPrompt(CharSequence prompt) {
- mPopup.setPromptText(prompt);
- }
-
- /**
- * Sets the prompt to display when the dialog is shown.
- * @param promptId the resource ID of the prompt to display when the dialog is shown
- */
- public void setPromptId(int promptId) {
- setPrompt(getContext().getText(promptId));
- }
-
- /**
- * @return The prompt to display when the dialog is shown
- */
- public CharSequence getPrompt() {
- return mPopup.getHintText();
- }
-
- int measureContentWidth(SpinnerAdapter adapter, Drawable background) {
- if (adapter == null) {
- return 0;
- }
-
- int width = 0;
- View itemView = null;
- int itemType = 0;
- final int widthMeasureSpec =
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- final int heightMeasureSpec =
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
- // Make sure the number of items we'll measure is capped. If it's a huge data set
- // with wildly varying sizes, oh well.
- int start = Math.max(0, getSelectedItemPosition());
- final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
- final int count = end - start;
- start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
- for (int i = start; i < end; i++) {
- final int positionType = adapter.getItemViewType(i);
- if (positionType != itemType) {
- itemType = positionType;
- itemView = null;
- }
- itemView = adapter.getView(i, itemView, this);
- if (itemView.getLayoutParams() == null) {
- itemView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- }
- itemView.measure(widthMeasureSpec, heightMeasureSpec);
- width = Math.max(width, itemView.getMeasuredWidth());
- }
-
- // Add background padding to measured width
- if (background != null) {
- background.getPadding(mTempRect);
- width += mTempRect.left + mTempRect.right;
- }
-
- return width;
- }
-
- @Override
- public Parcelable onSaveInstanceState() {
- final SavedState ss = new SavedState(super.onSaveInstanceState());
- ss.showDropdown = mPopup != null && mPopup.isShowing();
- return ss;
- }
-
- @Override
- public void onRestoreInstanceState(Parcelable state) {
- SavedState ss = (SavedState) state;
-
- super.onRestoreInstanceState(ss.getSuperState());
-
- if (ss.showDropdown) {
- ViewTreeObserver vto = getViewTreeObserver();
- if (vto != null) {
- final ViewTreeObserver.OnGlobalLayoutListener listener
- = new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (!mPopup.isShowing()) {
- mPopup.show();
- }
- final ViewTreeObserver vto = getViewTreeObserver();
- if (vto != null) {
- vto.removeGlobalOnLayoutListener(this);
- }
- }
- };
- vto.addOnGlobalLayoutListener(listener);
- }
- }
- }
-
- static class SavedState extends AbsSpinnerCompat.SavedState {
-
- boolean showDropdown;
-
- SavedState(Parcelable superState) {
- super(superState);
- }
-
- private SavedState(Parcel in) {
- super(in);
- showDropdown = in.readByte() != 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeByte((byte) (showDropdown ? 1 : 0));
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- /**
- * <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance into a
- * ListAdapter.</p>
- */
- private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
-
- private SpinnerAdapter mAdapter;
-
- private ListAdapter mListAdapter;
-
- /**
- * <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
- *
- * @param adapter the Adapter to transform into a ListAdapter
- */
- public DropDownAdapter(SpinnerAdapter adapter) {
- this.mAdapter = adapter;
- if (adapter instanceof ListAdapter) {
- this.mListAdapter = (ListAdapter) adapter;
- }
- }
-
- public int getCount() {
- return mAdapter == null ? 0 : mAdapter.getCount();
- }
-
- public Object getItem(int position) {
- return mAdapter == null ? null : mAdapter.getItem(position);
- }
-
- public long getItemId(int position) {
- return mAdapter == null ? -1 : mAdapter.getItemId(position);
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- return getDropDownView(position, convertView, parent);
- }
-
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
- return (mAdapter == null) ? null
- : mAdapter.getDropDownView(position, convertView, parent);
- }
-
- public boolean hasStableIds() {
- return mAdapter != null && mAdapter.hasStableIds();
- }
-
- public void registerDataSetObserver(DataSetObserver observer) {
- if (mAdapter != null) {
- mAdapter.registerDataSetObserver(observer);
- }
- }
-
- public void unregisterDataSetObserver(DataSetObserver observer) {
- if (mAdapter != null) {
- mAdapter.unregisterDataSetObserver(observer);
- }
- }
-
- /**
- * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call. Otherwise,
- * return true.
- */
- public boolean areAllItemsEnabled() {
- final ListAdapter adapter = mListAdapter;
- if (adapter != null) {
- return adapter.areAllItemsEnabled();
- } else {
- return true;
- }
- }
-
- /**
- * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call. Otherwise,
- * return true.
- */
- public boolean isEnabled(int position) {
- final ListAdapter adapter = mListAdapter;
- if (adapter != null) {
- return adapter.isEnabled(position);
- } else {
- return true;
- }
- }
-
- public int getItemViewType(int position) {
- return 0;
- }
-
- public int getViewTypeCount() {
- return 1;
- }
-
- public boolean isEmpty() {
- return getCount() == 0;
- }
- }
-
- /**
- * Implements some sort of popup selection interface for selecting a spinner option. Allows for
- * different spinner modes.
- */
- private interface SpinnerPopup {
-
- public void setAdapter(ListAdapter adapter);
-
- /**
- * Show the popup
- */
- public void show();
-
- /**
- * Dismiss the popup
- */
- public void dismiss();
-
- /**
- * @return true if the popup is showing, false otherwise.
- */
- public boolean isShowing();
-
- /**
- * Set hint text to be displayed to the user. This should provide a description of the
- * choice being made.
- *
- * @param hintText Hint text to set.
- */
- public void setPromptText(CharSequence hintText);
-
- public CharSequence getHintText();
-
- public void setBackgroundDrawable(Drawable bg);
-
- public void setVerticalOffset(int px);
-
- public void setHorizontalOffset(int px);
-
- public Drawable getBackground();
-
- public int getVerticalOffset();
-
- public int getHorizontalOffset();
- }
-
- private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
-
- private AlertDialog mPopup;
-
- private ListAdapter mListAdapter;
-
- private CharSequence mPrompt;
-
- public void dismiss() {
- if (mPopup != null) {
- mPopup.dismiss();
- mPopup = null;
- }
- }
-
- public boolean isShowing() {
- return mPopup != null ? mPopup.isShowing() : false;
- }
-
- public void setAdapter(ListAdapter adapter) {
- mListAdapter = adapter;
- }
-
- public void setPromptText(CharSequence hintText) {
- mPrompt = hintText;
- }
-
- public CharSequence getHintText() {
- return mPrompt;
- }
-
- public void show() {
- if (mListAdapter == null) {
- return;
- }
- AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
- if (mPrompt != null) {
- builder.setTitle(mPrompt);
- }
- mPopup = builder.setSingleChoiceItems(mListAdapter,
- getSelectedItemPosition(), this).create();
- mPopup.show();
- }
-
- public void onClick(DialogInterface dialog, int which) {
- setSelection(which);
- if (mOnItemClickListener != null) {
- performItemClick(null, which, mListAdapter.getItemId(which));
- }
- dismiss();
- }
-
- @Override
- public void setBackgroundDrawable(Drawable bg) {
- Log.e(TAG, "Cannot set popup background for MODE_DIALOG, ignoring");
- }
-
- @Override
- public void setVerticalOffset(int px) {
- Log.e(TAG, "Cannot set vertical offset for MODE_DIALOG, ignoring");
- }
-
- @Override
- public void setHorizontalOffset(int px) {
- Log.e(TAG, "Cannot set horizontal offset for MODE_DIALOG, ignoring");
- }
-
- @Override
- public Drawable getBackground() {
- return null;
- }
-
- @Override
- public int getVerticalOffset() {
- return 0;
- }
-
- @Override
- public int getHorizontalOffset() {
- return 0;
- }
- }
-
- private class DropdownPopup extends ListPopupWindow implements SpinnerPopup {
-
- private CharSequence mHintText;
-
- private ListAdapter mAdapter;
-
- public DropdownPopup(
- Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- setAnchorView(SpinnerCompat.this);
- setModal(true);
- setPromptPosition(POSITION_PROMPT_ABOVE);
-
- setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- SpinnerCompat.this.setSelection(position);
- if (mOnItemClickListener != null) {
- SpinnerCompat.this
- .performItemClick(v, position, mAdapter.getItemId(position));
- }
- dismiss();
- }
- });
- }
-
- @Override
- public void setAdapter(ListAdapter adapter) {
- super.setAdapter(adapter);
- mAdapter = adapter;
- }
-
- public CharSequence getHintText() {
- return mHintText;
- }
-
- public void setPromptText(CharSequence hintText) {
- // Hint text is ignored for dropdowns, but maintain it here.
- mHintText = hintText;
- }
-
- void computeContentWidth() {
- final Drawable background = getBackground();
- int hOffset = 0;
- if (background != null) {
- background.getPadding(mTempRect);
- hOffset = ViewUtils.isLayoutRtl(SpinnerCompat.this) ? mTempRect.right
- : -mTempRect.left;
- } else {
- mTempRect.left = mTempRect.right = 0;
- }
-
- final int spinnerPaddingLeft = SpinnerCompat.this.getPaddingLeft();
- final int spinnerPaddingRight = SpinnerCompat.this.getPaddingRight();
- final int spinnerWidth = SpinnerCompat.this.getWidth();
- if (mDropDownWidth == WRAP_CONTENT) {
- int contentWidth = measureContentWidth(
- (SpinnerAdapter) mAdapter, getBackground());
- final int contentWidthLimit = getContext().getResources()
- .getDisplayMetrics().widthPixels - mTempRect.left - mTempRect.right;
- if (contentWidth > contentWidthLimit) {
- contentWidth = contentWidthLimit;
- }
- setContentWidth(Math.max(
- contentWidth, spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight));
- } else if (mDropDownWidth == MATCH_PARENT) {
- setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
- } else {
- setContentWidth(mDropDownWidth);
- }
- if (ViewUtils.isLayoutRtl(SpinnerCompat.this)) {
- hOffset += spinnerWidth - spinnerPaddingRight - getWidth();
- } else {
- hOffset += spinnerPaddingLeft;
- }
- setHorizontalOffset(hOffset);
- }
-
- public void show(int textDirection, int textAlignment) {
- final boolean wasShowing = isShowing();
-
- computeContentWidth();
- setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
- super.show();
- final ListView listView = getListView();
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- //listView.setTextDirection(textDirection);
- //listView.setTextAlignment(textAlignment);
- setSelection(SpinnerCompat.this.getSelectedItemPosition());
-
- if (wasShowing) {
- // Skip setting up the layout/dismiss listener below. If we were previously
- // showing it will still stick around.
- return;
- }
-
- // Make sure we hide if our anchor goes away.
- // TODO: This might be appropriate to push all the way down to PopupWindow,
- // but it may have other side effects to investigate first. (Text editing handles, etc.)
- final ViewTreeObserver vto = getViewTreeObserver();
- if (vto != null) {
- final ViewTreeObserver.OnGlobalLayoutListener layoutListener
- = new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- computeContentWidth();
-
- // Use super.show here to update; we don't want to move the selected
- // position or adjust other things that would be reset otherwise.
- DropdownPopup.super.show();
- }
- };
- vto.addOnGlobalLayoutListener(layoutListener);
- setOnDismissListener(new PopupWindow.OnDismissListener() {
- @Override
- public void onDismiss() {
- final ViewTreeObserver vto = getViewTreeObserver();
- if (vto != null) {
- vto.removeGlobalOnLayoutListener(layoutListener);
- }
- }
- });
- }
- }
- }
-}
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java b/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
index 999fc6d..7bcaef7 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
@@ -90,7 +90,7 @@
R.drawable.abc_textfield_activated_mtrl_alpha,
R.drawable.abc_textfield_search_activated_mtrl_alpha,
R.drawable.abc_cab_background_top_mtrl_alpha,
- R.drawable.abc_text_cursor_mtrl_alpha
+ R.drawable.abc_text_cursor_material
};
/**
@@ -294,7 +294,9 @@
tint = createSwitchThumbColorStateList(context);
} else if (resId == R.drawable.abc_btn_default_mtrl_shape
|| resId == R.drawable.abc_btn_borderless_material) {
- tint = createButtonColorStateList(context);
+ tint = createDefaultButtonColorStateList(context);
+ } else if (resId == R.drawable.abc_btn_colored_material) {
+ tint = createColoredButtonColorStateList(context);
} else if (resId == R.drawable.abc_spinner_mtrl_am_alpha
|| resId == R.drawable.abc_spinner_textfield_background_material) {
tint = createSpinnerColorStateList(context);
@@ -480,12 +482,20 @@
return new ColorStateList(states, colors);
}
- private ColorStateList createButtonColorStateList(Context context) {
+ private ColorStateList createDefaultButtonColorStateList(Context context) {
+ return createButtonColorStateList(context, R.attr.colorButtonNormal);
+ }
+
+ private ColorStateList createColoredButtonColorStateList(Context context) {
+ return createButtonColorStateList(context, R.attr.colorAccent);
+ }
+
+ private ColorStateList createButtonColorStateList(Context context, int baseColorAttr) {
final int[][] states = new int[4][];
final int[] colors = new int[4];
int i = 0;
- final int colorButtonNormal = getThemeAttrColor(context, R.attr.colorButtonNormal);
+ final int baseColor = getThemeAttrColor(context, baseColorAttr);
final int colorControlHighlight = getThemeAttrColor(context, R.attr.colorControlHighlight);
// Disabled state
@@ -494,16 +504,16 @@
i++;
states[i] = ThemeUtils.PRESSED_STATE_SET;
- colors[i] = ColorUtils.compositeColors(colorControlHighlight, colorButtonNormal);
+ colors[i] = ColorUtils.compositeColors(colorControlHighlight, baseColor);
i++;
states[i] = ThemeUtils.FOCUSED_STATE_SET;
- colors[i] = ColorUtils.compositeColors(colorControlHighlight, colorButtonNormal);
+ colors[i] = ColorUtils.compositeColors(colorControlHighlight, baseColor);
i++;
// Default enabled state
states[i] = ThemeUtils.EMPTY_STATE_SET;
- colors[i] = colorButtonNormal;
+ colors[i] = baseColor;
i++;
return new ColorStateList(states, colors);
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java b/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
index 225f8e7..50e03c9 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/ToolbarWidgetWrapper.java
@@ -22,12 +22,14 @@
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
import android.support.v7.appcompat.R;
import android.support.v7.internal.view.menu.ActionMenuItem;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuPresenter;
import android.support.v7.widget.ActionMenuPresenter;
+import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
@@ -38,6 +40,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.Spinner;
import android.widget.SpinnerAdapter;
/**
@@ -56,12 +60,14 @@
private static final int AFFECTS_LOGO_MASK =
ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO;
+ // Default fade duration for fading in/out tool bar.
+ private static final long DEFAULT_FADE_DURATION_MS = 200;
private Toolbar mToolbar;
private int mDisplayOpts;
private View mTabView;
- private SpinnerCompat mSpinner;
+ private Spinner mSpinner;
private View mCustomView;
private Drawable mIcon;
@@ -241,11 +247,6 @@
}
@Override
- public boolean isSplit() {
- return false;
- }
-
- @Override
public boolean hasExpandedActionView() {
return mToolbar.hasExpandedActionView();
}
@@ -310,27 +311,6 @@
}
@Override
- public boolean canSplit() {
- return false;
- }
-
- @Override
- public void setSplitView(ViewGroup splitView) {
- }
-
- @Override
- public void setSplitToolbar(boolean split) {
- if (split) {
- throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar");
- }
- }
-
- @Override
- public void setSplitWhenNarrow(boolean splitWhenNarrow) {
- // Ignore.
- }
-
- @Override
public boolean hasIcon() {
return mIcon != null;
}
@@ -547,7 +527,7 @@
private void ensureSpinner() {
if (mSpinner == null) {
- mSpinner = new SpinnerCompat(getContext(), null, R.attr.actionDropDownStyle);
+ mSpinner = new AppCompatSpinner(getContext(), null, R.attr.actionDropDownStyle);
Toolbar.LayoutParams lp = new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
mSpinner.setLayoutParams(lp);
@@ -556,7 +536,7 @@
@Override
public void setDropdownParams(SpinnerAdapter adapter,
- AdapterViewCompat.OnItemSelectedListener listener) {
+ AdapterView.OnItemSelectedListener listener) {
ensureSpinner();
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(listener);
@@ -599,34 +579,48 @@
@Override
public void animateToVisibility(int visibility) {
- if (visibility == View.GONE) {
- ViewCompat.animate(mToolbar).alpha(0)
- .setListener(new ViewPropertyAnimatorListenerAdapter() {
- private boolean mCanceled = false;
- @Override
- public void onAnimationEnd(View view) {
- if (!mCanceled) {
- mToolbar.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void onAnimationCancel(View view) {
- mCanceled = true;
- }
- });
- } else if (visibility == View.VISIBLE) {
- ViewCompat.animate(mToolbar).alpha(1)
- .setListener(new ViewPropertyAnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(View view) {
- mToolbar.setVisibility(View.VISIBLE);
- }
- });
+ ViewPropertyAnimatorCompat anim = setupAnimatorToVisibility(visibility,
+ DEFAULT_FADE_DURATION_MS);
+ if (anim != null) {
+ anim.start();
}
}
@Override
+ public ViewPropertyAnimatorCompat setupAnimatorToVisibility(int visibility, long duration) {
+ if (visibility == View.GONE) {
+ ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(0f);
+ anim.setDuration(duration);
+ anim.setListener(new ViewPropertyAnimatorListenerAdapter() {
+ private boolean mCanceled = false;
+ @Override
+ public void onAnimationEnd(View view) {
+ if (!mCanceled) {
+ mToolbar.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(View view) {
+ mCanceled = true;
+ }
+ });
+ return anim;
+ } else if (visibility == View.VISIBLE) {
+ ViewPropertyAnimatorCompat anim = ViewCompat.animate(mToolbar).alpha(1f);
+ anim.setDuration(duration);
+ anim.setListener(new ViewPropertyAnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(View view) {
+ mToolbar.setVisibility(View.VISIBLE);
+ }
+ });
+ return anim;
+ }
+ return null;
+ }
+
+ @Override
public void setNavigationIcon(Drawable icon) {
mNavIcon = icon;
updateNavigationIcon();
@@ -708,9 +702,4 @@
return mToolbar.getMenu();
}
- @Override
- public int getPopupTheme() {
- return mToolbar.getPopupTheme();
- }
-
}
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
index bf167d6..7a84b08 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuPresenter.java
@@ -55,7 +55,9 @@
private static final String TAG = "ActionMenuPresenter";
- private View mOverflowButton;
+ private OverflowMenuButton mOverflowButton;
+ private Drawable mPendingOverflowIcon;
+ private boolean mPendingOverflowIconSet;
private boolean mReserveOverflow;
private boolean mReserveOverflowSet;
private int mWidthLimit;
@@ -110,6 +112,11 @@
if (mReserveOverflow) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mSystemContext);
+ if (mPendingOverflowIconSet) {
+ mOverflowButton.setImageDrawable(mPendingOverflowIcon);
+ mPendingOverflowIcon = null;
+ mPendingOverflowIconSet = false;
+ }
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
mOverflowButton.measure(spec, spec);
}
@@ -156,6 +163,24 @@
mExpandedActionViewsExclusive = isExclusive;
}
+ public void setOverflowIcon(Drawable icon) {
+ if (mOverflowButton != null) {
+ mOverflowButton.setImageDrawable(icon);
+ } else {
+ mPendingOverflowIconSet = true;
+ mPendingOverflowIcon = icon;
+ }
+ }
+
+ public Drawable getOverflowIcon() {
+ if (mOverflowButton != null) {
+ return mOverflowButton.getDrawable();
+ } else if (mPendingOverflowIconSet) {
+ return mPendingOverflowIcon;
+ }
+ return null;
+ }
+
@Override
public MenuView getMenuView(ViewGroup root) {
MenuView result = super.getMenuView(root);
diff --git a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
index b7c9821..0e47283 100644
--- a/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
+++ b/v7/appcompat/src/android/support/v7/widget/ActionMenuView.java
@@ -17,7 +17,10 @@
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.annotation.StyleRes;
import android.support.v7.internal.view.menu.ActionMenuItemView;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuItemImpl;
@@ -50,8 +53,6 @@
private MenuBuilder mMenu;
- private Context mContext;
-
/** Context against which to inflate popup menus. */
private Context mPopupContext;
@@ -75,7 +76,6 @@
public ActionMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
- mContext = context;
setBaselineAligned(false);
final float density = context.getResources().getDisplayMetrics().density;
mMinCellSize = (int) (MIN_CELL_SIZE * density);
@@ -91,13 +91,13 @@
* @param resId theme used to inflate popup menus
* @see #getPopupTheme()
*/
- public void setPopupTheme(int resId) {
+ public void setPopupTheme(@StyleRes int resId) {
if (mPopupTheme != resId) {
mPopupTheme = resId;
if (resId == 0) {
- mPopupContext = mContext;
+ mPopupContext = getContext();
} else {
- mPopupContext = new ContextThemeWrapper(mContext, resId);
+ mPopupContext = new ContextThemeWrapper(getContext(), resId);
}
}
}
@@ -544,6 +544,27 @@
dismissPopupMenus();
}
+ /**
+ * Set the icon to use for the overflow button.
+ *
+ * @param icon Drawable to set, may be null to clear the icon
+ */
+ public void setOverflowIcon(@Nullable Drawable icon) {
+ getMenu();
+ mPresenter.setOverflowIcon(icon);
+ }
+
+ /**
+ * Return the current drawable used as the overflow icon.
+ *
+ * @return The overflow icon drawable
+ */
+ @Nullable
+ public Drawable getOverflowIcon() {
+ getMenu();
+ return mPresenter.getOverflowIcon();
+ }
+
/** @hide */
public boolean isOverflowReserved() {
return mReserveOverflow;
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
index 285fbeb..a057677 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatAutoCompleteTextView.java
@@ -20,33 +20,41 @@
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintInfo;
import android.support.v7.internal.widget.TintManager;
import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.AutoCompleteTextView;
/**
- * A tint aware {@link android.widget.AutoCompleteTextView}.
- * <p>
- * This will automatically be used when you use {@link AutoCompleteTextView} in your layouts. You
- * should only need to manually use this class writing custom views.
+ * A {@link AutoCompleteTextView} which supports compatible features on older version of the
+ * platform, including:
+ * <ul>
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link AutoCompleteTextView} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatAutoCompleteTextView extends AutoCompleteTextView implements
TintableBackgroundView {
private static final int[] TINT_ATTRS = {
- android.R.attr.background,
android.R.attr.popupBackground
};
- private TintInfo mInternalBackgroundTint;
- private TintInfo mBackgroundTint;
private TintManager mTintManager;
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
+ private AppCompatTextHelper mTextHelper;
public AppCompatAutoCompleteTextView(Context context) {
this(context, null);
@@ -59,59 +67,57 @@
public AppCompatAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- mTintManager = a.getTintManager();
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
+ TINT_ATTRS, defStyleAttr, 0);
+ mTintManager = a.getTintManager();
+ if (a.hasValue(0)) {
+ setDropDownBackgroundDrawable(a.getDrawable(0));
+ }
+ a.recycle();
- if (a.hasValue(0)) {
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));
- if (tint != null) {
- setInternalBackgroundTint(tint);
- }
- }
- if (a.hasValue(1)) {
- setDropDownBackgroundDrawable(a.getDrawable(1));
- }
- a.recycle();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+ mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setDropDownBackgroundResource(@DrawableRes int resId) {
+ if (mTintManager != null) {
+ setDropDownBackgroundDrawable(mTintManager.getDrawable(resId));
+ } else {
+ super.setDropDownBackgroundResource(resId);
}
}
@Override
- public void setBackgroundResource(int resId) {
+ public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
- // Update the default background tint
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
}
@Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(background);
- // We don't know that this drawable is, so we need to clear the default background tint
- setInternalBackgroundTint(null);
- }
-
- @Override
- public void setDropDownBackgroundResource(int id) {
- setDropDownBackgroundDrawable(mTintManager.getDrawable(id));
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
+ }
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View,
- * android.content.res.ColorStateList)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
}
- mBackgroundTint.mTintList = tint;
- mBackgroundTint.mHasTintList = true;
-
- applySupportBackgroundTint();
}
/**
@@ -123,24 +129,21 @@
@Override
@Nullable
public ColorStateList getSupportBackgroundTintList() {
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
}
- mBackgroundTint.mTintMode = tintMode;
- mBackgroundTint.mHasTintMode = true;
-
- applySupportBackgroundTint();
}
/**
@@ -152,35 +155,23 @@
@Override
@Nullable
public PorterDuff.Mode getSupportBackgroundTintMode() {
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- applySupportBackgroundTint();
- }
-
- private void applySupportBackgroundTint() {
- if (getBackground() != null) {
- if (mBackgroundTint != null) {
- TintManager.tintViewBackground(this, mBackgroundTint);
- } else if (mInternalBackgroundTint != null) {
- TintManager.tintViewBackground(this, mInternalBackgroundTint);
- }
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
}
}
- private void setInternalBackgroundTint(ColorStateList tint) {
- if (tint != null) {
- if (mInternalBackgroundTint == null) {
- mInternalBackgroundTint = new TintInfo();
- }
- mInternalBackgroundTint.mTintList = tint;
- mInternalBackgroundTint.mHasTintList = true;
- } else {
- mInternalBackgroundTint = null;
+ @Override
+ public void setTextAppearance(Context context, int resId) {
+ super.setTextAppearance(context, resId);
+ if (mTextHelper != null) {
+ mTextHelper.onSetTextAppearance(context, resId);
}
- applySupportBackgroundTint();
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
new file mode 100644
index 0000000..7494b24
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.appcompat.R;
+import android.support.v7.graphics.drawable.DrawableUtils;
+import android.support.v7.internal.widget.TintInfo;
+import android.support.v7.internal.widget.TintManager;
+import android.util.AttributeSet;
+import android.view.View;
+
+class AppCompatBackgroundHelper {
+
+ private final View mView;
+ private final TintManager mTintManager;
+
+ private TintInfo mInternalBackgroundTint;
+ private TintInfo mBackgroundTint;
+
+ AppCompatBackgroundHelper(View view, TintManager tintManager) {
+ mView = view;
+ mTintManager = tintManager;
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ TypedArray a = mView.getContext().obtainStyledAttributes(attrs,
+ R.styleable.ViewBackgroundHelper, defStyleAttr, 0);
+ try {
+ if (a.hasValue(R.styleable.ViewBackgroundHelper_android_background)) {
+ ColorStateList tint = mTintManager.getTintList(
+ a.getResourceId(R.styleable.ViewBackgroundHelper_android_background, -1));
+ if (tint != null) {
+ setInternalBackgroundTint(tint);
+ }
+ }
+ if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTint)) {
+ ViewCompat.setBackgroundTintList(mView,
+ a.getColorStateList(R.styleable.ViewBackgroundHelper_backgroundTint));
+ }
+ if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTintMode)) {
+ ViewCompat.setBackgroundTintMode(mView,
+ DrawableUtils.parseTintMode(
+ a.getInt(R.styleable.ViewBackgroundHelper_backgroundTintMode, -1),
+ null));
+ }
+ } finally {
+ a.recycle();
+ }
+ }
+
+ void onSetBackgroundResource(int resId) {
+ // Update the default background tint
+ setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ }
+
+ void onSetBackgroundDrawable(Drawable background) {
+ // We don't know that this drawable is, so we need to clear the default background tint
+ setInternalBackgroundTint(null);
+ }
+
+ void setSupportBackgroundTintList(ColorStateList tint) {
+ if (mBackgroundTint == null) {
+ mBackgroundTint = new TintInfo();
+ }
+ mBackgroundTint.mTintList = tint;
+ mBackgroundTint.mHasTintList = true;
+
+ applySupportBackgroundTint();
+ }
+
+ ColorStateList getSupportBackgroundTintList() {
+ return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
+ }
+
+ void setSupportBackgroundTintMode(PorterDuff.Mode tintMode) {
+ if (mBackgroundTint == null) {
+ mBackgroundTint = new TintInfo();
+ }
+ mBackgroundTint.mTintMode = tintMode;
+ mBackgroundTint.mHasTintMode = true;
+
+ applySupportBackgroundTint();
+ }
+
+ PorterDuff.Mode getSupportBackgroundTintMode() {
+ return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+ }
+
+ void applySupportBackgroundTint() {
+ if (mView.getBackground() != null) {
+ if (mBackgroundTint != null) {
+ TintManager.tintViewBackground(mView, mBackgroundTint);
+ } else if (mInternalBackgroundTint != null) {
+ TintManager.tintViewBackground(mView, mInternalBackgroundTint);
+ }
+ }
+ }
+
+ void setInternalBackgroundTint(ColorStateList tint) {
+ if (tint != null) {
+ if (mInternalBackgroundTint == null) {
+ mInternalBackgroundTint = new TintInfo();
+ }
+ mInternalBackgroundTint.mTintList = tint;
+ mInternalBackgroundTint.mHasTintList = true;
+ } else {
+ mInternalBackgroundTint = null;
+ }
+ applySupportBackgroundTint();
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
index 3c6917d..91d69c8 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatButton.java
@@ -18,38 +18,39 @@
import android.content.Context;
import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.os.Build;
+import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
import android.support.v7.internal.text.AllCapsTransformationMethod;
-import android.support.v7.internal.widget.ThemeUtils;
-import android.support.v7.internal.widget.TintInfo;
import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
/**
- * A tint aware {@link android.widget.Button}.
- * <p>
- * This will automatically be used when you use {@link android.widget.Button} in your layouts. You
- * should only need to manually use this class when writing custom views.
+ * A {@link Button} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.Button} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatButton extends Button implements TintableBackgroundView {
- private static final int[] TINT_ATTRS = {
- android.R.attr.background
- };
-
- private TintInfo mInternalBackgroundTint;
- private TintInfo mBackgroundTint;
- private TintManager mTintManager;
+ private final TintManager mTintManager;
+ private final AppCompatBackgroundHelper mBackgroundTintHelper;
+ private final AppCompatTextHelper mTextHelper;
public AppCompatButton(Context context) {
this(context, null);
@@ -62,95 +63,41 @@
public AppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- if (a.hasValue(0)) {
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));
- if (tint != null) {
- setInternalBackgroundTint(tint);
- }
- }
- mTintManager = a.getTintManager();
- a.recycle();
- }
+ mTintManager = TintManager.get(getContext());
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
- // First read the TextAppearance style id
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView,
- defStyleAttr, 0);
- final int ap = a.getResourceId(R.styleable.AppCompatTextView_android_textAppearance, -1);
- a.recycle();
-
- // Now check TextAppearance's textAllCaps value
- if (ap != -1) {
- TypedArray appearance = context.obtainStyledAttributes(ap, R.styleable.TextAppearance);
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) {
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false));
- }
- appearance.recycle();
- }
-
- // Now read the style's value
- a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView, defStyleAttr, 0);
- if (a.hasValue(R.styleable.AppCompatTextView_textAllCaps)) {
- setAllCaps(a.getBoolean(R.styleable.AppCompatTextView_textAllCaps, false));
- }
- a.recycle();
-
- final ColorStateList textColors = getTextColors();
- if (textColors != null && !textColors.isStateful()) {
- // If we have a ColorStateList which isn't stateful, create one which includes
- // a disabled state
-
- final int disabledTextColor;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- // Pre-Lollipop, we will use textColorSecondary with android:disabledAlpha
- // applied
- disabledTextColor = ThemeUtils.getDisabledThemeAttrColor(context,
- android.R.attr.textColorSecondary);
- } else {
- // With certain styles on Lollipop, there is a StateListAnimator which sets
- // an alpha on the whole view, so we don't need to apply disabledAlpha to
- // textColorSecondary
- disabledTextColor = ThemeUtils.getThemeAttrColor(context,
- android.R.attr.textColorSecondary);
- }
-
- setTextColor(ThemeUtils.createDisabledStateList(
- textColors.getDefaultColor(), disabledTextColor));
- }
+ mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
- public void setBackgroundResource(int resId) {
+ public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
- // Update the default background tint
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
}
@Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(background);
- // We don't know that this drawable is, so we need to clear the default background tint
- setInternalBackgroundTint(null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
+ }
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View,
- * android.content.res.ColorStateList)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
}
- mBackgroundTint.mTintList = tint;
- mBackgroundTint.mHasTintList = true;
-
- applySupportBackgroundTint();
}
/**
@@ -162,24 +109,21 @@
@Override
@Nullable
public ColorStateList getSupportBackgroundTintList() {
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
}
- mBackgroundTint.mTintMode = tintMode;
- mBackgroundTint.mHasTintMode = true;
-
- applySupportBackgroundTint();
}
/**
@@ -191,36 +135,24 @@
@Override
@Nullable
public PorterDuff.Mode getSupportBackgroundTintMode() {
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- applySupportBackgroundTint();
- }
-
- private void applySupportBackgroundTint() {
- if (getBackground() != null) {
- if (mBackgroundTint != null) {
- TintManager.tintViewBackground(this, mBackgroundTint);
- } else if (mInternalBackgroundTint != null) {
- TintManager.tintViewBackground(this, mInternalBackgroundTint);
- }
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
}
}
- private void setInternalBackgroundTint(ColorStateList tint) {
- if (tint != null) {
- if (mInternalBackgroundTint == null) {
- mInternalBackgroundTint = new TintInfo();
- }
- mInternalBackgroundTint.mTintList = tint;
- mInternalBackgroundTint.mHasTintList = true;
- } else {
- mInternalBackgroundTint = null;
+ @Override
+ public void setTextAppearance(Context context, int resId) {
+ super.setTextAppearance(context, resId);
+ if (mTextHelper != null) {
+ mTextHelper.onSetTextAppearance(context, resId);
}
- applySupportBackgroundTint();
}
@Override
@@ -235,19 +167,18 @@
info.setClassName(Button.class.getName());
}
- public void setAllCaps(boolean allCaps) {
- setTransformationMethod(allCaps ? new AllCapsTransformationMethod(getContext()) : null);
- }
-
- @Override
- public void setTextAppearance(Context context, int resId) {
- super.setTextAppearance(context, resId);
-
- TypedArray appearance = context.obtainStyledAttributes(resId, R.styleable.TextAppearance);
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) {
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false));
+ /**
+ * Sets the properties of this field to transform input to ALL CAPS
+ * display. This may use a "small caps" formatting if available.
+ * This setting will be ignored if this field is editable or selectable.
+ *
+ * This call replaces the current transformation method. Disabling this
+ * will not necessarily restore the previous behavior from before this
+ * was enabled.
+ */
+ public void setSupportAllCaps(boolean allCaps) {
+ if (mTextHelper != null) {
+ mTextHelper.setAllCaps(allCaps);
}
- appearance.recycle();
}
-
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
index 6cbcdd1..1ad2c77 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckBox.java
@@ -17,29 +17,35 @@
package android.support.v7.widget;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.widget.TintableCompoundButton;
import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.CheckBox;
/**
- * A tint aware {@link android.widget.CheckBox}.
- * <p>
- * This will automatically be used when you use {@link android.widget.CheckBox} in your layouts.
- * You should only need to manually use this class when writing custom views.
+ * A {@link CheckBox} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.widget.CompoundButtonCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#buttonTint} and
+ * {@link R.attr#buttonTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link CheckBox} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
-public class AppCompatCheckBox extends CheckBox {
-
- private static final int[] TINT_ATTRS = {
- android.R.attr.button
- };
+public class AppCompatCheckBox extends CheckBox implements TintableCompoundButton {
private TintManager mTintManager;
- private Drawable mButtonDrawable;
+ private AppCompatCompoundButtonHelper mCompoundButtonHelper;
public AppCompatCheckBox(Context context) {
this(context, null);
@@ -51,43 +57,77 @@
public AppCompatCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
-
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- setButtonDrawable(a.getDrawable(0));
- a.recycle();
-
- mTintManager = a.getTintManager();
- }
+ mTintManager = TintManager.get(context);
+ mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager);
+ mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setButtonDrawable(Drawable buttonDrawable) {
super.setButtonDrawable(buttonDrawable);
- mButtonDrawable = buttonDrawable;
+ if (mCompoundButtonHelper != null) {
+ mCompoundButtonHelper.onSetButtonDrawable();
+ }
}
@Override
public void setButtonDrawable(@DrawableRes int resId) {
- if (mTintManager != null) {
- setButtonDrawable(mTintManager.getDrawable(resId));
- } else {
- super.setButtonDrawable(resId);
- }
+ setButtonDrawable(mTintManager != null
+ ? mTintManager.getDrawable(resId)
+ : ContextCompat.getDrawable(getContext(), resId));
}
@Override
public int getCompoundPaddingLeft() {
- int padding = super.getCompoundPaddingLeft();
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll
- // workaround that here
- if (mButtonDrawable != null) {
- padding += mButtonDrawable.getIntrinsicWidth();
- }
- }
- return padding;
+ final int value = super.getCompoundPaddingLeft();
+ return mCompoundButtonHelper != null
+ ? mCompoundButtonHelper.getCompoundPaddingLeft(value)
+ : value;
}
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Override
+ public void setSupportButtonTintList(@Nullable ColorStateList tint) {
+ if (mCompoundButtonHelper != null) {
+ mCompoundButtonHelper.setSupportButtonTintList(tint);
+ }
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Nullable
+ @Override
+ public ColorStateList getSupportButtonTintList() {
+ return mCompoundButtonHelper != null
+ ? mCompoundButtonHelper.getSupportButtonTintList()
+ : null;
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Override
+ public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+ if (mCompoundButtonHelper != null) {
+ mCompoundButtonHelper.setSupportButtonTintMode(tintMode);
+ }
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Nullable
+ @Override
+ public PorterDuff.Mode getSupportButtonTintMode() {
+ return mCompoundButtonHelper != null
+ ? mCompoundButtonHelper.getSupportButtonTintMode()
+ : null;
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
index 04836c6..4776b83 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCheckedTextView.java
@@ -18,17 +18,16 @@
import android.content.Context;
import android.support.annotation.DrawableRes;
-import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.TintManager;
import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.CheckedTextView;
/**
- * A tint aware {@link android.widget.CheckedTextView}.
- * <p>
- * This will automatically be used when you use {@link android.widget.CheckedTextView} in your
- * layouts. You should only need to manually use this class when writing custom views.
+ * A {@link CheckedTextView} which supports compatible features on older version of the platform.
+ *
+ * <p>This will automatically be used when you use {@link CheckedTextView} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatCheckedTextView extends CheckedTextView {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
new file mode 100644
index 0000000..20c3667
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatCompoundButtonHelper.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.widget.CompoundButtonCompat;
+import android.support.v7.appcompat.R;
+import android.support.v7.graphics.drawable.DrawableUtils;
+import android.support.v7.internal.widget.TintManager;
+import android.util.AttributeSet;
+import android.widget.CompoundButton;
+
+class AppCompatCompoundButtonHelper {
+
+ private final CompoundButton mView;
+ private final TintManager mTintManager;
+
+ private ColorStateList mButtonTintList = null;
+ private PorterDuff.Mode mButtonTintMode = null;
+ private boolean mHasButtonTint = false;
+ private boolean mHasButtonTintMode = false;
+
+ private boolean mSkipNextApply;
+
+ /**
+ * Interface which allows us to directly set a button, bypass any calls back to ourselves.
+ */
+ interface DirectSetButtonDrawableInterface {
+ void setButtonDrawable(Drawable buttonDrawable);
+ }
+
+ AppCompatCompoundButtonHelper(CompoundButton view, TintManager tintManager) {
+ mView = view;
+ mTintManager = tintManager;
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton,
+ defStyleAttr, 0);
+ try {
+ if (a.hasValue(R.styleable.CompoundButton_android_button)) {
+ final int resourceId = a.getResourceId(
+ R.styleable.CompoundButton_android_button, 0);
+ if (resourceId != 0) {
+ mView.setButtonDrawable(mTintManager.getDrawable(resourceId));
+ }
+ }
+ if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
+ CompoundButtonCompat.setButtonTintList(mView,
+ a.getColorStateList(R.styleable.CompoundButton_buttonTint));
+ }
+ if (a.hasValue(R.styleable.CompoundButton_buttonTintMode)) {
+ CompoundButtonCompat.setButtonTintMode(mView,
+ DrawableUtils.parseTintMode(
+ a.getInt(R.styleable.CompoundButton_buttonTintMode, -1),
+ null));
+ }
+ } finally {
+ a.recycle();
+ }
+ }
+
+ void setSupportButtonTintList(ColorStateList tint) {
+ mButtonTintList = tint;
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ ColorStateList getSupportButtonTintList() {
+ return mButtonTintList;
+ }
+
+ void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+ mButtonTintMode = tintMode;
+ mHasButtonTintMode = true;
+
+ applyButtonTint();
+ }
+
+ PorterDuff.Mode getSupportButtonTintMode() {
+ return mButtonTintMode;
+ }
+
+ void onSetButtonDrawable() {
+ if (mSkipNextApply) {
+ mSkipNextApply = false;
+ return;
+ }
+
+ mSkipNextApply = true;
+ applyButtonTint();
+ }
+
+ void applyButtonTint() {
+ Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
+
+ if (buttonDrawable != null && (mHasButtonTint || mHasButtonTintMode)) {
+ buttonDrawable = DrawableCompat.wrap(buttonDrawable);
+ buttonDrawable = buttonDrawable.mutate();
+ if (mHasButtonTint) {
+ DrawableCompat.setTintList(buttonDrawable, mButtonTintList);
+ }
+ if (mHasButtonTintMode) {
+ DrawableCompat.setTintMode(buttonDrawable, mButtonTintMode);
+ }
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (buttonDrawable.isStateful()) {
+ buttonDrawable.setState(mView.getDrawableState());
+ }
+ mView.setButtonDrawable(buttonDrawable);
+ }
+ }
+
+ int getCompoundPaddingLeft(int superValue) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll
+ // workaround that here
+ Drawable buttonDrawable = CompoundButtonCompat.getButtonDrawable(mView);
+ if (buttonDrawable != null) {
+ superValue += buttonDrawable.getIntrinsicWidth();
+ }
+ }
+ return superValue;
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java b/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
index 8df271f..885fd6d 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java
@@ -20,31 +20,35 @@
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintInfo;
import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.EditText;
/**
- * A tint aware {@link android.widget.EditText}.
- * <p>
- * This will automatically be used when you use {@link android.widget.EditText} in your
- * layouts. You should only need to manually use this class when writing custom views.
+ * A {@link EditText} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link android.widget.EditText} in your
+ * layouts. You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatEditText extends EditText implements TintableBackgroundView {
- private static final int[] TINT_ATTRS = {
- android.R.attr.background
- };
-
- private TintInfo mInternalBackgroundTint;
- private TintInfo mBackgroundTint;
private TintManager mTintManager;
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
+ private AppCompatTextHelper mTextHelper;
public AppCompatEditText(Context context) {
this(context, null);
@@ -57,50 +61,41 @@
public AppCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- if (a.hasValue(0)) {
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));
- if (tint != null) {
- setInternalBackgroundTint(tint);
- }
- }
- mTintManager = a.getTintManager();
- a.recycle();
- }
+ mTintManager = TintManager.get(getContext());
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+ mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
- public void setBackgroundResource(int resId) {
+ public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
- // Update the default background tint
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
}
@Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(background);
- // We don't know that this drawable is, so we need to clear the default background tint
- setInternalBackgroundTint(null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
+ }
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View,
- * android.content.res.ColorStateList)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
}
- mBackgroundTint.mTintList = tint;
- mBackgroundTint.mHasTintList = true;
-
- applySupportBackgroundTint();
}
/**
@@ -112,24 +107,21 @@
@Override
@Nullable
public ColorStateList getSupportBackgroundTintList() {
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
}
- mBackgroundTint.mTintMode = tintMode;
- mBackgroundTint.mHasTintMode = true;
-
- applySupportBackgroundTint();
}
/**
@@ -141,35 +133,23 @@
@Override
@Nullable
public PorterDuff.Mode getSupportBackgroundTintMode() {
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- applySupportBackgroundTint();
- }
-
- private void applySupportBackgroundTint() {
- if (getBackground() != null) {
- if (mBackgroundTint != null) {
- TintManager.tintViewBackground(this, mBackgroundTint);
- } else if (mInternalBackgroundTint != null) {
- TintManager.tintViewBackground(this, mInternalBackgroundTint);
- }
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
}
}
- private void setInternalBackgroundTint(ColorStateList tint) {
- if (tint != null) {
- if (mInternalBackgroundTint == null) {
- mInternalBackgroundTint = new TintInfo();
- }
- mInternalBackgroundTint.mTintList = tint;
- mInternalBackgroundTint.mHasTintList = true;
- } else {
- mInternalBackgroundTint = null;
+ @Override
+ public void setTextAppearance(Context context, int resId) {
+ super.setTextAppearance(context, resId);
+ if (mTextHelper != null) {
+ mTextHelper.onSetTextAppearance(context, resId);
}
- applySupportBackgroundTint();
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
index 7334cc4..6f97adb 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
@@ -25,29 +25,36 @@
import android.support.v4.view.TintableBackgroundView;
import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.TintContextWrapper;
-import android.support.v7.internal.widget.TintInfo;
import android.support.v7.internal.widget.TintManager;
import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.MultiAutoCompleteTextView;
/**
- * A tint aware {@link android.widget.MultiAutoCompleteTextView}.
- * <p>
- * This will automatically be used when you use {@link android.widget.MultiAutoCompleteTextView}
- * in your layouts. You should only need to manually use this class when writing custom views.
+ * A {@link MultiAutoCompleteTextView} which supports compatible features on older version of the
+ * platform, including:
+ * <ul>
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link MultiAutoCompleteTextView} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatMultiAutoCompleteTextView extends MultiAutoCompleteTextView
implements TintableBackgroundView {
private static final int[] TINT_ATTRS = {
- android.R.attr.background,
android.R.attr.popupBackground
};
- private TintInfo mInternalBackgroundTint;
- private TintInfo mBackgroundTint;
private TintManager mTintManager;
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
+ private AppCompatTextHelper mTextHelper;
public AppCompatMultiAutoCompleteTextView(Context context) {
this(context, null);
@@ -60,63 +67,57 @@
public AppCompatMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- mTintManager = a.getTintManager();
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
+ TINT_ATTRS, defStyleAttr, 0);
+ mTintManager = a.getTintManager();
+ if (a.hasValue(0)) {
+ setDropDownBackgroundDrawable(a.getDrawable(0));
+ }
+ a.recycle();
- if (a.hasValue(0)) {
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));
- if (tint != null) {
- setInternalBackgroundTint(tint);
- }
- }
- if (a.hasValue(1)) {
- setDropDownBackgroundDrawable(a.getDrawable(1));
- }
- a.recycle();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+ mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr);
+ }
+
+ @Override
+ public void setDropDownBackgroundResource(@DrawableRes int resId) {
+ if (mTintManager != null) {
+ setDropDownBackgroundDrawable(mTintManager.getDrawable(resId));
+ } else {
+ super.setDropDownBackgroundResource(resId);
}
}
@Override
- public void setBackgroundResource(int resId) {
+ public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
- // Update the default background tint
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
}
@Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(background);
- // We don't know that this drawable is, so we need to clear the default background tint
- setInternalBackgroundTint(null);
- }
-
- @Override
- public void setDropDownBackgroundResource(@DrawableRes int id) {
- if (mTintManager != null) {
- setDropDownBackgroundDrawable(mTintManager.getDrawable(id));
- } else {
- super.setDropDownBackgroundResource(id);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
}
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View,
- * android.content.res.ColorStateList)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View, ColorStateList)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
}
- mBackgroundTint.mTintList = tint;
- mBackgroundTint.mHasTintList = true;
-
- applySupportBackgroundTint();
}
/**
@@ -128,24 +129,21 @@
@Override
@Nullable
public ColorStateList getSupportBackgroundTintList() {
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, PorterDuff.Mode)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
}
- mBackgroundTint.mTintMode = tintMode;
- mBackgroundTint.mHasTintMode = true;
-
- applySupportBackgroundTint();
}
/**
@@ -157,35 +155,23 @@
@Override
@Nullable
public PorterDuff.Mode getSupportBackgroundTintMode() {
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- applySupportBackgroundTint();
- }
-
- private void applySupportBackgroundTint() {
- if (getBackground() != null) {
- if (mBackgroundTint != null) {
- TintManager.tintViewBackground(this, mBackgroundTint);
- } else if (mInternalBackgroundTint != null) {
- TintManager.tintViewBackground(this, mInternalBackgroundTint);
- }
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
}
}
- private void setInternalBackgroundTint(ColorStateList tint) {
- if (tint != null) {
- if (mInternalBackgroundTint == null) {
- mInternalBackgroundTint = new TintInfo();
- }
- mInternalBackgroundTint.mTintList = tint;
- mInternalBackgroundTint.mHasTintList = true;
- } else {
- mInternalBackgroundTint = null;
+ @Override
+ public void setTextAppearance(Context context, int resId) {
+ super.setTextAppearance(context, resId);
+ if (mTextHelper != null) {
+ mTextHelper.onSetTextAppearance(context, resId);
}
- applySupportBackgroundTint();
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
index a9df4dc..0d928fc 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRadioButton.java
@@ -17,29 +17,35 @@
package android.support.v7.widget;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.support.annotation.DrawableRes;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.widget.TintableCompoundButton;
import android.support.v7.appcompat.R;
import android.support.v7.internal.widget.TintManager;
-import android.support.v7.internal.widget.TintTypedArray;
import android.util.AttributeSet;
import android.widget.RadioButton;
/**
- * A tint aware {@link android.widget.RadioButton}.
- * <p>
- * This will automatically be used when you use {@link android.widget.RadioButton} in your
- * layouts. You should only need to manually use this class when writing custom views.
+ * A {@link RadioButton} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.widget.CompoundButtonCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#buttonTint} and
+ * {@link R.attr#buttonTintMode}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link RadioButton} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
-public class AppCompatRadioButton extends RadioButton {
-
- private static final int[] TINT_ATTRS = {
- android.R.attr.button
- };
+public class AppCompatRadioButton extends RadioButton implements TintableCompoundButton {
private TintManager mTintManager;
- private Drawable mButtonDrawable;
+ private AppCompatCompoundButtonHelper mCompoundButtonHelper;
public AppCompatRadioButton(Context context) {
this(context, null);
@@ -51,42 +57,77 @@
public AppCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
-
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- setButtonDrawable(a.getDrawable(0));
- a.recycle();
-
- mTintManager = a.getTintManager();
- }
+ mTintManager = TintManager.get(context);
+ mCompoundButtonHelper = new AppCompatCompoundButtonHelper(this, mTintManager);
+ mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setButtonDrawable(Drawable buttonDrawable) {
super.setButtonDrawable(buttonDrawable);
- mButtonDrawable = buttonDrawable;
+ if (mCompoundButtonHelper != null) {
+ mCompoundButtonHelper.onSetButtonDrawable();
+ }
}
@Override
- public void setButtonDrawable(@DrawableRes int resid) {
- if (mTintManager != null) {
- setButtonDrawable(mTintManager.getDrawable(resid));
- } else {
- super.setButtonDrawable(resid);
- }
+ public void setButtonDrawable(@DrawableRes int resId) {
+ setButtonDrawable(mTintManager != null
+ ? mTintManager.getDrawable(resId)
+ : ContextCompat.getDrawable(getContext(), resId));
}
@Override
public int getCompoundPaddingLeft() {
- int padding = super.getCompoundPaddingLeft();
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Before JB-MR1 the button drawable wasn't taken into account for padding. We'll
- // workaround that here
- if (mButtonDrawable != null) {
- padding += mButtonDrawable.getIntrinsicWidth();
- }
+ final int value = super.getCompoundPaddingLeft();
+ return mCompoundButtonHelper != null
+ ? mCompoundButtonHelper.getCompoundPaddingLeft(value)
+ : value;
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Override
+ public void setSupportButtonTintList(@Nullable ColorStateList tint) {
+ if (mCompoundButtonHelper != null) {
+ mCompoundButtonHelper.setSupportButtonTintList(tint);
}
- return padding;
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Nullable
+ @Override
+ public ColorStateList getSupportButtonTintList() {
+ return mCompoundButtonHelper != null
+ ? mCompoundButtonHelper.getSupportButtonTintList()
+ : null;
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Override
+ public void setSupportButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+ if (mCompoundButtonHelper != null) {
+ mCompoundButtonHelper.setSupportButtonTintMode(tintMode);
+ }
+ }
+
+ /**
+ * This should be accessed from {@link android.support.v4.widget.CompoundButtonCompat}
+ * @hide
+ */
+ @Nullable
+ @Override
+ public PorterDuff.Mode getSupportButtonTintMode() {
+ return mCompoundButtonHelper != null
+ ? mCompoundButtonHelper.getSupportButtonTintMode()
+ : null;
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
index daf2650..51811a8 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatRatingBar.java
@@ -38,10 +38,10 @@
import android.widget.RatingBar;
/**
- * A tint aware {@link android.widget.RatingBar}.
- * <p>
- * This will automatically be used when you use {@link android.widget.RatingBar} in your
- * layouts. You should only need to manually use this class when writing custom views.
+ * A {@link RatingBar} which supports compatible features on older version of the platform.
+ *
+ * <p>This will automatically be used when you use {@link RatingBar} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatRatingBar extends RatingBar {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
index 4ce1275..2c3426c 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatSpinner.java
@@ -16,122 +16,460 @@
package android.support.v7.widget;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
import android.graphics.PorterDuff;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.v4.view.TintableBackgroundView;
+import android.support.v4.view.ViewCompat;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.widget.TintInfo;
+import android.support.v7.internal.view.ContextThemeWrapper;
import android.support.v7.internal.widget.TintManager;
import android.support.v7.internal.widget.TintTypedArray;
+import android.support.v7.internal.widget.ViewUtils;
import android.util.AttributeSet;
-import android.widget.ListPopupWindow;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.AdapterView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.PopupWindow;
import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
-import java.lang.reflect.Field;
/**
- * A tint aware {@link android.widget.Spinner}.
- * <p>
- * This will automatically be used when you use {@link android.widget.Spinner} in your
- * layouts. You should only need to manually use this class when writing custom views.
+ * A {@link Spinner} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Allows dynamic tint of it background via the background tint methods in
+ * {@link android.support.v4.view.ViewCompat}.</li>
+ * <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ * {@link R.attr#backgroundTintMode}.</li>
+ * <li>Allows setting of the popups theme using {@link R.attr#popupTheme}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link Spinner} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatSpinner extends Spinner implements TintableBackgroundView {
- private static final int[] TINT_ATTRS = {
- android.R.attr.background,
- android.R.attr.popupBackground
- };
+ private static final boolean IS_AT_LEAST_M =
+ "MNC".equals(Build.VERSION.CODENAME) || Build.VERSION.SDK_INT >= 23;
+ private static final boolean IS_AT_LEAST_JB = Build.VERSION.SDK_INT >= 16;
- private TintInfo mInternalBackgroundTint;
- private TintInfo mBackgroundTint;
+ private static final int[] ATTRS_ANDROID_SPINNERMODE = {android.R.attr.spinnerMode};
+
+ private static final int MAX_ITEMS_MEASURED = 15;
+
+ private static final String TAG = "AppCompatSpinner";
+
+ private static final int MODE_DIALOG = 0;
+ private static final int MODE_DROPDOWN = 1;
+ private static final int MODE_THEME = -1;
+
private TintManager mTintManager;
+ private AppCompatBackgroundHelper mBackgroundTintHelper;
+
+ /** Context used to inflate the popup window or dialog. */
+ private Context mPopupContext;
+
+ /** Forwarding listener used to implement drag-to-open. */
+ private ListPopupWindow.ForwardingListener mForwardingListener;
+
+ /** Temporary holder for setAdapter() calls from the super constructor. */
+ private SpinnerAdapter mTempAdapter;
+
+ private boolean mPopupSet;
+
+ private DropdownPopup mPopup;
+
+ private int mDropDownWidth;
+
+ private final Rect mTempRect = new Rect();
+
+ /**
+ * Construct a new spinner with the given context's theme.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ */
public AppCompatSpinner(Context context) {
this(context, null);
}
+ /**
+ * Construct a new spinner with the given context's theme and the supplied
+ * mode of displaying choices. <code>mode</code> may be one of
+ * {@link #MODE_DIALOG} or {@link #MODE_DROPDOWN}.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param mode Constant describing how the user will select choices from the spinner.
+ * @see #MODE_DIALOG
+ * @see #MODE_DROPDOWN
+ */
+ public AppCompatSpinner(Context context, int mode) {
+ this(context, null, R.attr.spinnerStyle, mode);
+ }
+
+ /**
+ * Construct a new spinner with the given context's theme and the supplied attribute set.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ */
public AppCompatSpinner(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.spinnerStyle);
}
+ /**
+ * Construct a new spinner with the given context's theme, the supplied attribute set,
+ * and default style attribute.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ */
public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, MODE_THEME);
+ }
+
+ /**
+ * Construct a new spinner with the given context's theme, the supplied attribute set,
+ * and default style. <code>mode</code> may be one of {@link #MODE_DIALOG} or
+ * {@link #MODE_DROPDOWN} and determines how the user will select choices from the spinner.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ * @param mode Constant describing how the user will select choices from the spinner.
+ * @see #MODE_DIALOG
+ * @see #MODE_DROPDOWN
+ */
+ public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
+ this(context, attrs, defStyleAttr, mode, null);
+ }
+
+
+ /**
+ * Constructs a new spinner with the given context's theme, the supplied
+ * attribute set, default styles, popup mode (one of {@link #MODE_DIALOG}
+ * or {@link #MODE_DROPDOWN}), and the context against which the popup
+ * should be inflated.
+ *
+ * @param context The context against which the view is inflated, which
+ * provides access to the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default
+ * values for the view. Can be 0 to not look for
+ * defaults.
+ * @param mode Constant describing how the user will select choices from
+ * the spinner.
+ * @param popupTheme The theme against which the dialog or dropdown popup
+ * should be inflated. May be {@code null} to use the
+ * view theme. If set, this will override any value
+ * specified by
+ * {@link R.styleable#Spinner_popupTheme}.
+ * @see #MODE_DIALOG
+ * @see #MODE_DROPDOWN
+ */
+ public AppCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode,
+ Resources.Theme popupTheme) {
super(context, attrs, defStyleAttr);
- if (TintManager.SHOULD_BE_USED) {
- TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
- TINT_ATTRS, defStyleAttr, 0);
- if (a.hasValue(0)) {
- ColorStateList tint = a.getTintManager().getTintList(a.getResourceId(0, -1));
- if (tint != null) {
- setInternalBackgroundTint(tint);
+ TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
+ R.styleable.Spinner, defStyleAttr, 0);
+
+ mTintManager = a.getTintManager();
+ mBackgroundTintHelper = new AppCompatBackgroundHelper(this, mTintManager);
+
+ if (popupTheme != null) {
+ mPopupContext = new ContextThemeWrapper(context, popupTheme);
+ } else {
+ final int popupThemeResId = a.getResourceId(R.styleable.Spinner_popupTheme, 0);
+ if (popupThemeResId != 0) {
+ mPopupContext = new ContextThemeWrapper(context, popupThemeResId);
+ } else {
+ // If we're running on a < M device, we'll use the current context and still handle
+ // any dropdown popup
+ mPopupContext = !IS_AT_LEAST_M ? context : null;
+ }
+ }
+
+ if (mPopupContext != null) {
+ if (mode == MODE_THEME) {
+ if (Build.VERSION.SDK_INT >= 11) {
+ // If we're running on API v11+ we will try and read android:spinnerMode
+ TypedArray aa = null;
+ try {
+ aa = context.obtainStyledAttributes(attrs, ATTRS_ANDROID_SPINNERMODE,
+ defStyleAttr, 0);
+ if (aa.hasValue(0)) {
+ mode = aa.getInt(0, MODE_DIALOG);
+ }
+ } catch (Exception e) {
+ Log.i(TAG, "Could not read android:spinnerMode", e);
+ } finally {
+ if (aa != null) {
+ aa.recycle();
+ }
+ }
+ } else {
+ // Else, we use a default mode of dropdown
+ mode = MODE_DROPDOWN;
}
}
- if (a.hasValue(1)) {
- final Drawable popupBackground = a.getDrawable(1);
- if (Build.VERSION.SDK_INT >= 16) {
- setPopupBackgroundDrawable(popupBackground);
- } else if (Build.VERSION.SDK_INT >= 11) {
- setPopupBackgroundDrawableV11(this, popupBackground);
- }
+
+ if (mode == MODE_DROPDOWN) {
+ final DropdownPopup popup = new DropdownPopup(mPopupContext, attrs, defStyleAttr);
+ final TintTypedArray pa = TintTypedArray.obtainStyledAttributes(
+ mPopupContext, attrs, R.styleable.Spinner, defStyleAttr, 0);
+ mDropDownWidth = pa.getLayoutDimension(R.styleable.Spinner_android_dropDownWidth,
+ LayoutParams.WRAP_CONTENT);
+ popup.setBackgroundDrawable(
+ pa.getDrawable(R.styleable.Spinner_android_popupBackground));
+ popup.setPromptText(a.getString(R.styleable.Spinner_android_prompt));
+ pa.recycle();
+
+ mPopup = popup;
+ mForwardingListener = new ListPopupWindow.ForwardingListener(this) {
+ @Override
+ public ListPopupWindow getPopup() {
+ return popup;
+ }
+
+ @Override
+ public boolean onForwardingStarted() {
+ if (!mPopup.isShowing()) {
+ mPopup.show();
+ }
+ return true;
+ }
+ };
}
- mTintManager = a.getTintManager();
- a.recycle();
+ }
+ a.recycle();
+
+ mPopupSet = true;
+
+ // Base constructors can call setAdapter before we initialize mPopup.
+ // Finish setting things up if this happened.
+ if (mTempAdapter != null) {
+ setAdapter(mTempAdapter);
+ mTempAdapter = null;
+ }
+
+ mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+ }
+
+ /**
+ * @return the context used to inflate the Spinner's popup or dialog window
+ */
+ public Context getPopupContext() {
+ if (mPopup != null) {
+ return mPopupContext;
+ } else if (IS_AT_LEAST_M) {
+ return super.getPopupContext();
+ }
+ return null;
+ }
+
+ public void setPopupBackgroundDrawable(Drawable background) {
+ if (mPopup != null) {
+ mPopup.setBackgroundDrawable(background);
+ } else if (IS_AT_LEAST_JB) {
+ super.setPopupBackgroundDrawable(background);
+ }
+ }
+
+ public void setPopupBackgroundResource(@DrawableRes int resId) {
+ setPopupBackgroundDrawable(getPopupContext().getDrawable(resId));
+ }
+
+ public Drawable getPopupBackground() {
+ if (mPopup != null) {
+ return mPopup.getBackground();
+ } else if (IS_AT_LEAST_JB) {
+ return super.getPopupBackground();
+ }
+ return null;
+ }
+
+ public void setDropDownVerticalOffset(int pixels) {
+ if (mPopup != null) {
+ mPopup.setVerticalOffset(pixels);
+ } else if (IS_AT_LEAST_JB) {
+ super.setDropDownVerticalOffset(pixels);
+ }
+ }
+
+ public int getDropDownVerticalOffset() {
+ if (mPopup != null) {
+ return mPopup.getVerticalOffset();
+ } else if (IS_AT_LEAST_JB) {
+ return super.getDropDownVerticalOffset();
+ }
+ return 0;
+ }
+
+ public void setDropDownHorizontalOffset(int pixels) {
+ if (mPopup != null) {
+ mPopup.setHorizontalOffset(pixels);
+ } else if (IS_AT_LEAST_JB) {
+ super.setDropDownHorizontalOffset(pixels);
+ }
+ }
+
+ /**
+ * Get the configured horizontal offset in pixels for the spinner's popup window of choices.
+ * Only valid in {@link #MODE_DROPDOWN}; other modes will return 0.
+ *
+ * @return Horizontal offset in pixels
+ */
+ public int getDropDownHorizontalOffset() {
+ if (mPopup != null) {
+ return mPopup.getHorizontalOffset();
+ } else if (IS_AT_LEAST_JB) {
+ return super.getDropDownHorizontalOffset();
+ }
+ return 0;
+ }
+
+ public void setDropDownWidth(int pixels) {
+ if (mPopup != null) {
+ mDropDownWidth = pixels;
+ } else if (IS_AT_LEAST_JB) {
+ super.setDropDownWidth(pixels);
+ }
+ }
+
+ public int getDropDownWidth() {
+ if (mPopup != null) {
+ return mDropDownWidth;
+ } else if (IS_AT_LEAST_JB) {
+ return super.getDropDownWidth();
+ }
+ return 0;
+ }
+
+ @Override
+ public void setAdapter(SpinnerAdapter adapter) {
+ // The super constructor may call setAdapter before we're prepared.
+ // Postpone doing anything until we've finished construction.
+ if (!mPopupSet) {
+ mTempAdapter = adapter;
+ return;
+ }
+
+ super.setAdapter(adapter);
+
+ if (mPopup != null) {
+ final Context popupContext = mPopupContext == null ? getContext() : mPopupContext;
+ mPopup.setAdapter(new DropDownAdapter(adapter, popupContext.getTheme()));
}
}
@Override
- public void setBackgroundResource(int resId) {
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mPopup != null && mPopup.isShowing()) {
+ mPopup.dismiss();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mForwardingListener != null && mForwardingListener.onTouch(this, event)) {
+ return true;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
+ final int measuredWidth = getMeasuredWidth();
+ setMeasuredDimension(Math.min(Math.max(measuredWidth,
+ compatMeasureContentWidth(getAdapter(), getBackground())),
+ MeasureSpec.getSize(widthMeasureSpec)),
+ getMeasuredHeight());
+ }
+ }
+
+ @Override
+ public boolean performClick() {
+ if (mPopup != null && !mPopup.isShowing()) {
+ mPopup.show();
+ return true;
+ }
+ return super.performClick();
+ }
+
+ @Override
+ public void setPrompt(CharSequence prompt) {
+ if (mPopup != null) {
+ mPopup.setPromptText(prompt);
+ } else {
+ super.setPrompt(prompt);
+ }
+ }
+
+ @Override
+ public CharSequence getPrompt() {
+ return mPopup != null ? mPopup.getHintText() : super.getPrompt();
+ }
+
+ @Override
+ public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
- // Update the default background tint
- setInternalBackgroundTint(mTintManager != null ? mTintManager.getTintList(resId) : null);
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundResource(resId);
+ }
}
@Override
public void setBackgroundDrawable(Drawable background) {
super.setBackgroundDrawable(background);
- // We don't know that this drawable is, so we need to clear the default background tint
- setInternalBackgroundTint(null);
- }
-
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- private static void setPopupBackgroundDrawableV11(Spinner view, Drawable background) {
- try {
- Field popupField = Spinner.class.getDeclaredField("mPopup");
- popupField.setAccessible(true);
-
- Object popup = popupField.get(view);
-
- if (popup instanceof ListPopupWindow) {
- ((ListPopupWindow) popup).setBackgroundDrawable(background);
- }
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.onSetBackgroundDrawable(background);
}
}
/**
* This should be accessed via
* {@link android.support.v4.view.ViewCompat#setBackgroundTintList(android.view.View,
- * android.content.res.ColorStateList)}
+ * ColorStateList)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintList(tint);
}
- mBackgroundTint.mTintList = tint;
- mBackgroundTint.mHasTintList = true;
-
- applySupportBackgroundTint();
}
/**
@@ -143,24 +481,22 @@
@Override
@Nullable
public ColorStateList getSupportBackgroundTintList() {
- return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
}
/**
* This should be accessed via
- * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode)}
+ * {@link android.support.v4.view.ViewCompat#setBackgroundTintMode(android.view.View,
+ * PorterDuff.Mode)}
*
* @hide
*/
@Override
public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
- if (mBackgroundTint == null) {
- mBackgroundTint = new TintInfo();
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
}
- mBackgroundTint.mTintMode = tintMode;
- mBackgroundTint.mHasTintMode = true;
-
- applySupportBackgroundTint();
}
/**
@@ -172,35 +508,311 @@
@Override
@Nullable
public PorterDuff.Mode getSupportBackgroundTintMode() {
- return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+ return mBackgroundTintHelper != null
+ ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- applySupportBackgroundTint();
- }
-
- private void applySupportBackgroundTint() {
- if (getBackground() != null) {
- if (mBackgroundTint != null) {
- TintManager.tintViewBackground(this, mBackgroundTint);
- } else if (mInternalBackgroundTint != null) {
- TintManager.tintViewBackground(this, mInternalBackgroundTint);
- }
+ if (mBackgroundTintHelper != null) {
+ mBackgroundTintHelper.applySupportBackgroundTint();
}
}
- private void setInternalBackgroundTint(ColorStateList tint) {
- if (tint != null) {
- if (mInternalBackgroundTint == null) {
- mInternalBackgroundTint = new TintInfo();
- }
- mInternalBackgroundTint.mTintList = tint;
- mInternalBackgroundTint.mHasTintList = true;
- } else {
- mInternalBackgroundTint = null;
+ private int compatMeasureContentWidth(SpinnerAdapter adapter, Drawable background) {
+ if (adapter == null) {
+ return 0;
}
- applySupportBackgroundTint();
+
+ int width = 0;
+ View itemView = null;
+ int itemType = 0;
+ final int widthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED);
+
+ // Make sure the number of items we'll measure is capped. If it's a huge data set
+ // with wildly varying sizes, oh well.
+ int start = Math.max(0, getSelectedItemPosition());
+ final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
+ final int count = end - start;
+ start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
+ for (int i = start; i < end; i++) {
+ final int positionType = adapter.getItemViewType(i);
+ if (positionType != itemType) {
+ itemType = positionType;
+ itemView = null;
+ }
+ itemView = adapter.getView(i, itemView, this);
+ if (itemView.getLayoutParams() == null) {
+ itemView.setLayoutParams(new LayoutParams(
+ LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+ }
+ itemView.measure(widthMeasureSpec, heightMeasureSpec);
+ width = Math.max(width, itemView.getMeasuredWidth());
+ }
+
+ // Add background padding to measured width
+ if (background != null) {
+ background.getPadding(mTempRect);
+ width += mTempRect.left + mTempRect.right;
+ }
+
+ return width;
+ }
+
+ /**
+ * <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
+ * into a ListAdapter.</p>
+ */
+ private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
+
+ private SpinnerAdapter mAdapter;
+
+ private ListAdapter mListAdapter;
+
+ /**
+ * Creates a new ListAdapter wrapper for the specified adapter.
+ *
+ * @param adapter the SpinnerAdapter to transform into a ListAdapter
+ * @param dropDownTheme the theme against which to inflate drop-down
+ * views, may be {@null} to use default theme
+ */
+ public DropDownAdapter(@Nullable SpinnerAdapter adapter,
+ @Nullable Resources.Theme dropDownTheme) {
+ mAdapter = adapter;
+
+ if (adapter instanceof ListAdapter) {
+ mListAdapter = (ListAdapter) adapter;
+ }
+
+ if (dropDownTheme != null) {
+ if (IS_AT_LEAST_M && adapter instanceof android.widget.ThemedSpinnerAdapter) {
+ final android.widget.ThemedSpinnerAdapter themedAdapter =
+ (android.widget.ThemedSpinnerAdapter) adapter;
+ if (themedAdapter.getDropDownViewTheme() != dropDownTheme) {
+ themedAdapter.setDropDownViewTheme(dropDownTheme);
+ }
+ } else if (adapter instanceof ThemedSpinnerAdapter) {
+ final ThemedSpinnerAdapter themedAdapter = (ThemedSpinnerAdapter) adapter;
+ if (themedAdapter.getDropDownViewTheme() == null) {
+ themedAdapter.setDropDownViewTheme(dropDownTheme);
+ }
+ }
+ }
+ }
+
+ public int getCount() {
+ return mAdapter == null ? 0 : mAdapter.getCount();
+ }
+
+ public Object getItem(int position) {
+ return mAdapter == null ? null : mAdapter.getItem(position);
+ }
+
+ public long getItemId(int position) {
+ return mAdapter == null ? -1 : mAdapter.getItemId(position);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return getDropDownView(position, convertView, parent);
+ }
+
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ return (mAdapter == null) ? null
+ : mAdapter.getDropDownView(position, convertView, parent);
+ }
+
+ public boolean hasStableIds() {
+ return mAdapter != null && mAdapter.hasStableIds();
+ }
+
+ public void registerDataSetObserver(DataSetObserver observer) {
+ if (mAdapter != null) {
+ mAdapter.registerDataSetObserver(observer);
+ }
+ }
+
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ if (mAdapter != null) {
+ mAdapter.unregisterDataSetObserver(observer);
+ }
+ }
+
+ /**
+ * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
+ * Otherwise, return true.
+ */
+ public boolean areAllItemsEnabled() {
+ final ListAdapter adapter = mListAdapter;
+ if (adapter != null) {
+ return adapter.areAllItemsEnabled();
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
+ * Otherwise, return true.
+ */
+ public boolean isEnabled(int position) {
+ final ListAdapter adapter = mListAdapter;
+ if (adapter != null) {
+ return adapter.isEnabled(position);
+ } else {
+ return true;
+ }
+ }
+
+ public int getItemViewType(int position) {
+ return 0;
+ }
+
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ public boolean isEmpty() {
+ return getCount() == 0;
+ }
+ }
+
+ private class DropdownPopup extends ListPopupWindow {
+ private CharSequence mHintText;
+ private ListAdapter mAdapter;
+ private final Rect mVisibleRect = new Rect();
+
+ public DropdownPopup(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ setAnchorView(AppCompatSpinner.this);
+ setModal(true);
+ setPromptPosition(POSITION_PROMPT_ABOVE);
+
+ setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+ AppCompatSpinner.this.setSelection(position);
+ if (getOnItemClickListener() != null) {
+ AppCompatSpinner.this
+ .performItemClick(v, position, mAdapter.getItemId(position));
+ }
+ dismiss();
+ }
+ });
+ }
+
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ super.setAdapter(adapter);
+ mAdapter = adapter;
+ }
+
+ public CharSequence getHintText() {
+ return mHintText;
+ }
+
+ public void setPromptText(CharSequence hintText) {
+ // Hint text is ignored for dropdowns, but maintain it here.
+ mHintText = hintText;
+ }
+
+ void computeContentWidth() {
+ final Drawable background = getBackground();
+ int hOffset = 0;
+ if (background != null) {
+ background.getPadding(mTempRect);
+ hOffset = ViewUtils.isLayoutRtl(AppCompatSpinner.this) ? mTempRect.right
+ : -mTempRect.left;
+ } else {
+ mTempRect.left = mTempRect.right = 0;
+ }
+
+ final int spinnerPaddingLeft = AppCompatSpinner.this.getPaddingLeft();
+ final int spinnerPaddingRight = AppCompatSpinner.this.getPaddingRight();
+ final int spinnerWidth = AppCompatSpinner.this.getWidth();
+ if (mDropDownWidth == WRAP_CONTENT) {
+ int contentWidth = compatMeasureContentWidth(
+ (SpinnerAdapter) mAdapter, getBackground());
+ final int contentWidthLimit = getContext().getResources()
+ .getDisplayMetrics().widthPixels - mTempRect.left - mTempRect.right;
+ if (contentWidth > contentWidthLimit) {
+ contentWidth = contentWidthLimit;
+ }
+ setContentWidth(Math.max(
+ contentWidth, spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight));
+ } else if (mDropDownWidth == MATCH_PARENT) {
+ setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
+ } else {
+ setContentWidth(mDropDownWidth);
+ }
+ if (ViewUtils.isLayoutRtl(AppCompatSpinner.this)) {
+ hOffset += spinnerWidth - spinnerPaddingRight - getWidth();
+ } else {
+ hOffset += spinnerPaddingLeft;
+ }
+ setHorizontalOffset(hOffset);
+ }
+
+ public void show() {
+ final boolean wasShowing = isShowing();
+
+ computeContentWidth();
+
+ setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
+ super.show();
+ final ListView listView = getListView();
+ listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ setSelection(AppCompatSpinner.this.getSelectedItemPosition());
+
+ if (wasShowing) {
+ // Skip setting up the layout/dismiss listener below. If we were previously
+ // showing it will still stick around.
+ return;
+ }
+
+ // Make sure we hide if our anchor goes away.
+ // TODO: This might be appropriate to push all the way down to PopupWindow,
+ // but it may have other side effects to investigate first. (Text editing handles, etc.)
+ final ViewTreeObserver vto = getViewTreeObserver();
+ if (vto != null) {
+ final ViewTreeObserver.OnGlobalLayoutListener layoutListener
+ = new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (!isVisibleToUser(AppCompatSpinner.this)) {
+ dismiss();
+ } else {
+ computeContentWidth();
+
+ // Use super.show here to update; we don't want to move the selected
+ // position or adjust other things that would be reset otherwise.
+ DropdownPopup.super.show();
+ }
+ }
+ };
+ vto.addOnGlobalLayoutListener(layoutListener);
+ setOnDismissListener(new PopupWindow.OnDismissListener() {
+ @Override
+ public void onDismiss() {
+ final ViewTreeObserver vto = getViewTreeObserver();
+ if (vto != null) {
+ vto.removeGlobalOnLayoutListener(layoutListener);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Simplified version of the the hidden View.isVisibleToUser()
+ */
+ private boolean isVisibleToUser(View view) {
+ return ViewCompat.isAttachedToWindow(view) && view.getGlobalVisibleRect(mVisibleRect);
+ }
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
new file mode 100644
index 0000000..7a75e76
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextHelper.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.support.v7.appcompat.R;
+import android.support.v7.internal.text.AllCapsTransformationMethod;
+import android.support.v7.internal.widget.ThemeUtils;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+class AppCompatTextHelper {
+
+ private static final int[] VIEW_ATTRS = {android.R.attr.textAppearance};
+ private static final int[] TEXT_APPEARANCE_ATTRS = {R.attr.textAllCaps};
+
+ private final TextView mView;
+
+ AppCompatTextHelper(TextView view) {
+ mView = view;
+ }
+
+ void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
+ Context context = mView.getContext();
+
+ // First read the TextAppearance style id
+ TypedArray a = context.obtainStyledAttributes(attrs, VIEW_ATTRS, defStyleAttr, 0);
+ final int ap = a.getResourceId(0, -1);
+ a.recycle();
+
+ // Now check TextAppearance's textAllCaps value
+ if (ap != -1) {
+ TypedArray appearance = context.obtainStyledAttributes(ap, R.styleable.TextAppearance);
+ if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) {
+ setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false));
+ }
+ appearance.recycle();
+ }
+
+ // Now read the style's value
+ a = context.obtainStyledAttributes(attrs, TEXT_APPEARANCE_ATTRS, defStyleAttr, 0);
+ if (a.hasValue(0)) {
+ setAllCaps(a.getBoolean(0, false));
+ }
+ a.recycle();
+
+ final ColorStateList textColors = mView.getTextColors();
+ if (textColors != null && !textColors.isStateful()) {
+ // If we have a ColorStateList which isn't stateful, create one which includes
+ // a disabled state
+
+ final int disabledTextColor;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ // Pre-Lollipop, we will use textColorSecondary with android:disabledAlpha
+ // applied
+ disabledTextColor = ThemeUtils.getDisabledThemeAttrColor(context,
+ android.R.attr.textColorSecondary);
+ } else {
+ // With certain styles on Lollipop, there is a StateListAnimator which sets
+ // an alpha on the whole view, so we don't need to apply disabledAlpha to
+ // textColorSecondary
+ disabledTextColor = ThemeUtils.getThemeAttrColor(context,
+ android.R.attr.textColorSecondary);
+ }
+
+ mView.setTextColor(ThemeUtils.createDisabledStateList(
+ textColors.getDefaultColor(), disabledTextColor));
+ }
+ }
+
+ void onSetTextAppearance(Context context, int resId) {
+ TypedArray appearance = context.obtainStyledAttributes(resId, TEXT_APPEARANCE_ATTRS);
+ if (appearance.hasValue(0)) {
+ setAllCaps(appearance.getBoolean(0, false));
+ }
+ appearance.recycle();
+ }
+
+ void setAllCaps(boolean allCaps) {
+ mView.setTransformationMethod(allCaps
+ ? new AllCapsTransformationMethod(mView.getContext())
+ : null);
+ }
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java b/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
index a05c4a8..ccedfe0 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatTextView.java
@@ -17,21 +17,25 @@
package android.support.v7.widget;
import android.content.Context;
-import android.content.res.TypedArray;
import android.support.v7.appcompat.R;
-import android.support.v7.internal.text.AllCapsTransformationMethod;
import android.util.AttributeSet;
import android.widget.TextView;
/**
- * A {@link android.widget.TextView} which supports compatible features on older version of the
- * platform.
- * <p>
- * This will automatically be used when you use {@link android.widget.TextView} in your
- * layouts. You should only need to manually use this class when writing custom views.
+ * A {@link TextView} which supports compatible features on older version of the platform,
+ * including:
+ * <ul>
+ * <li>Supports {@link R.attr#textAllCaps} style attribute which works back to
+ * {@link android.os.Build.VERSION_CODES#ECLAIR_MR1 Eclair MR1}.</li>
+ * </ul>
+ *
+ * <p>This will automatically be used when you use {@link TextView} in your layouts.
+ * You should only need to manually use this class when writing custom views.</p>
*/
public class AppCompatTextView extends TextView {
+ private AppCompatTextHelper mTextHelper;
+
public AppCompatTextView(Context context) {
this(context, null);
}
@@ -40,44 +44,18 @@
this(context, attrs, android.R.attr.textViewStyle);
}
- public AppCompatTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
+ public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
- // First read the TextAppearance style id
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView,
- defStyle, 0);
- final int ap = a.getResourceId(R.styleable.AppCompatTextView_android_textAppearance, -1);
- a.recycle();
-
- // Now check TextAppearance's textAllCaps value
- if (ap != -1) {
- TypedArray appearance = context.obtainStyledAttributes(ap, R.styleable.TextAppearance);
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) {
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false));
- }
- appearance.recycle();
- }
-
- // Now read the style's value
- a = context.obtainStyledAttributes(attrs, R.styleable.AppCompatTextView, defStyle, 0);
- if (a.hasValue(R.styleable.AppCompatTextView_textAllCaps)) {
- setAllCaps(a.getBoolean(R.styleable.AppCompatTextView_textAllCaps, false));
- }
- a.recycle();
- }
-
- public void setAllCaps(boolean allCaps) {
- setTransformationMethod(allCaps ? new AllCapsTransformationMethod(getContext()) : null);
+ mTextHelper = new AppCompatTextHelper(this);
+ mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
-
- TypedArray appearance = context.obtainStyledAttributes(resId, R.styleable.TextAppearance);
- if (appearance.hasValue(R.styleable.TextAppearance_textAllCaps)) {
- setAllCaps(appearance.getBoolean(R.styleable.TextAppearance_textAllCaps, false));
+ if (mTextHelper != null) {
+ mTextHelper.onSetTextAppearance(context, resId);
}
- appearance.recycle();
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java b/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
index 5b7d333..5c4dde8 100644
--- a/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
+++ b/v7/appcompat/src/android/support/v7/widget/PopupMenu.java
@@ -114,6 +114,29 @@
}
/**
+ * Sets the gravity used to align the popup window to its anchor view.
+ * <p>
+ * If the popup is showing, calling this method will take effect only
+ * the next time the popup is shown.
+ *
+ * @param gravity the gravity used to align the popup window
+ *
+ * @see #getGravity()
+ */
+ public void setGravity(int gravity) {
+ mPopup.setGravity(gravity);
+ }
+
+ /**
+ * @return the gravity used to align the popup window to its anchor view
+ *
+ * @see #setGravity(int)
+ */
+ public int getGravity() {
+ return mPopup.getGravity();
+ }
+
+ /**
* Returns an {@link android.view.View.OnTouchListener} that can be added to the anchor view
* to implement drag-to-open behavior.
* <p>
diff --git a/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java b/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
new file mode 100644
index 0000000..95974a6
--- /dev/null
+++ b/v7/appcompat/src/android/support/v7/widget/ThemedSpinnerAdapter.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SpinnerAdapter;
+
+/**
+ * An extension of SpinnerAdapter that is capable of inflating drop-down views
+ * against a different theme than normal views.
+ * <p>
+ * Classes that implement this interface should use the theme provided to
+ * {@link #setDropDownViewTheme(Theme)} when creating views in
+ * {@link SpinnerAdapter#getDropDownView(int, View, ViewGroup)}.
+ */
+public interface ThemedSpinnerAdapter extends SpinnerAdapter {
+ /**
+ * Sets the {@link Resources.Theme} against which drop-down views are
+ * inflated.
+ *
+ * @param theme the context against which to inflate drop-down views, or
+ * {@code null} to use the default theme
+ * @see SpinnerAdapter#getDropDownView(int, View, ViewGroup)
+ */
+ void setDropDownViewTheme(@Nullable Resources.Theme theme);
+
+ /**
+ * Returns the value previously set by a call to
+ * {@link #setDropDownViewTheme(Theme)}.
+ *
+ * @return the {@link Resources.Theme} against which drop-down views are
+ * inflated, or {@code null} if one has not been explicitly set
+ */
+ @Nullable
+ Resources.Theme getDropDownViewTheme();
+}
diff --git a/v7/appcompat/src/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
index 970bbbb..0e8e318 100644
--- a/v7/appcompat/src/android/support/v7/widget/Toolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
@@ -17,12 +17,20 @@
package android.support.v7.widget;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.MenuRes;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.support.annotation.StyleRes;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MarginLayoutParamsCompat;
import android.support.v4.view.MenuItemCompat;
@@ -30,6 +38,7 @@
import android.support.v4.view.ViewCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.appcompat.R;
+import android.support.v7.graphics.drawable.DrawableUtils;
import android.support.v7.internal.view.SupportMenuInflater;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuItemImpl;
@@ -38,6 +47,7 @@
import android.support.v7.internal.view.menu.SubMenuBuilder;
import android.support.v7.internal.widget.DecorToolbar;
import android.support.v7.internal.widget.RtlSpacingHelper;
+import android.support.v7.internal.widget.TintInfo;
import android.support.v7.internal.widget.TintManager;
import android.support.v7.internal.widget.TintTypedArray;
import android.support.v7.internal.widget.ToolbarWidgetWrapper;
@@ -79,7 +89,9 @@
* <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close,
* collapse, done or another glyph of the app's choosing. This button should always be used
* to access other navigational destinations within the container of the Toolbar and
- * its signified content or otherwise leave the current context signified by the Toolbar.</li>
+ * its signified content or otherwise leave the current context signified by the Toolbar.
+ * The navigation button is vertically aligned within the Toolbar's minimum height,
+ * if set.</li>
* <li><em>A branded logo image.</em> This may extend to the height of the bar and can be
* arbitrarily wide.</li>
* <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current
@@ -95,8 +107,9 @@
* <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the
* end of the Toolbar offering a few
* <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons">
- * frequent, important or typical</a> actions along with an optional overflow menu for
- * additional actions.</li>
+ * frequent, important or typical</a> actions along with an optional overflow menu for
+ * additional actions. Action buttons are vertically aligned within the Toolbar's
+ * minimum height, if set.</li>
* </ul>
* </p>
*
@@ -152,6 +165,9 @@
// Clear me after use.
private final ArrayList<View> mTempViews = new ArrayList<View>();
+ // Used to hold views that will be removed while we have an expanded action view.
+ private final ArrayList<View> mHiddenViews = new ArrayList<>();
+
private final int[] mTempMargins = new int[2];
private OnMenuItemClickListener mOnMenuItemClickListener;
@@ -271,6 +287,23 @@
setNavigationContentDescription(navDesc);
}
+ final Drawable logo = a.getDrawable(R.styleable.Toolbar_logo);
+ if (logo != null) {
+ setLogo(logo);
+ }
+
+ final CharSequence logoDesc = a.getText(R.styleable.Toolbar_logoDescription);
+ if (!TextUtils.isEmpty(logoDesc)) {
+ setLogoDescription(logoDesc);
+ }
+
+ if (a.hasValue(R.styleable.Toolbar_titleTextColor)) {
+ setTitleTextColor(a.getColor(R.styleable.Toolbar_titleTextColor, 0xffffffff));
+ }
+
+ if (a.hasValue(R.styleable.Toolbar_subtitleTextColor)) {
+ setSubtitleTextColor(a.getColor(R.styleable.Toolbar_subtitleTextColor, 0xffffffff));
+ }
a.recycle();
// Keep the TintManager in case we need it later
@@ -284,7 +317,7 @@
* @param resId theme used to inflate popup menus
* @see #getPopupTheme()
*/
- public void setPopupTheme(int resId) {
+ public void setPopupTheme(@StyleRes int resId) {
if (mPopupTheme != resId) {
mPopupTheme = resId;
if (resId == 0) {
@@ -320,7 +353,7 @@
*
* @param resId ID of a drawable resource
*/
- public void setLogo(int resId) {
+ public void setLogo(@DrawableRes int resId) {
setLogo(mTintManager.getDrawable(resId));
}
@@ -439,12 +472,12 @@
public void setLogo(Drawable drawable) {
if (drawable != null) {
ensureLogoView();
- if (mLogoView.getParent() == null) {
- addSystemView(mLogoView);
- updateChildVisibilityForExpandedActionView(mLogoView);
+ if (!isChildOrHidden(mLogoView)) {
+ addSystemView(mLogoView, true);
}
- } else if (mLogoView != null && mLogoView.getParent() != null) {
+ } else if (mLogoView != null && isChildOrHidden(mLogoView)) {
removeView(mLogoView);
+ mHiddenViews.remove(mLogoView);
}
if (mLogoView != null) {
mLogoView.setImageDrawable(drawable);
@@ -470,7 +503,7 @@
*
* @param resId String resource id
*/
- public void setLogoDescription(int resId) {
+ public void setLogoDescription(@StringRes int resId) {
setLogoDescription(getContext().getText(resId));
}
@@ -555,7 +588,7 @@
*
* @param resId Resource ID of a string to set as the title
*/
- public void setTitle(int resId) {
+ public void setTitle(@StringRes int resId) {
setTitle(getContext().getText(resId));
}
@@ -581,12 +614,12 @@
mTitleTextView.setTextColor(mTitleTextColor);
}
}
- if (mTitleTextView.getParent() == null) {
- addSystemView(mTitleTextView);
- updateChildVisibilityForExpandedActionView(mTitleTextView);
+ if (!isChildOrHidden(mTitleTextView)) {
+ addSystemView(mTitleTextView, true);
}
- } else if (mTitleTextView != null && mTitleTextView.getParent() != null) {
+ } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
removeView(mTitleTextView);
+ mHiddenViews.remove(mTitleTextView);
}
if (mTitleTextView != null) {
mTitleTextView.setText(title);
@@ -610,7 +643,7 @@
*
* @param resId String resource ID
*/
- public void setSubtitle(int resId) {
+ public void setSubtitle(@StringRes int resId) {
setSubtitle(getContext().getText(resId));
}
@@ -635,12 +668,12 @@
mSubtitleTextView.setTextColor(mSubtitleTextColor);
}
}
- if (mSubtitleTextView.getParent() == null) {
- addSystemView(mSubtitleTextView);
- updateChildVisibilityForExpandedActionView(mSubtitleTextView);
+ if (!isChildOrHidden(mSubtitleTextView)) {
+ addSystemView(mSubtitleTextView, true);
}
- } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) {
+ } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) {
removeView(mSubtitleTextView);
+ mHiddenViews.remove(mSubtitleTextView);
}
if (mSubtitleTextView != null) {
mSubtitleTextView.setText(subtitle);
@@ -652,7 +685,7 @@
* Sets the text color, size, style, hint color, and highlight color
* from the specified TextAppearance resource.
*/
- public void setTitleTextAppearance(Context context, int resId) {
+ public void setTitleTextAppearance(Context context, @StyleRes int resId) {
mTitleTextAppearance = resId;
if (mTitleTextView != null) {
mTitleTextView.setTextAppearance(context, resId);
@@ -663,7 +696,7 @@
* Sets the text color, size, style, hint color, and highlight color
* from the specified TextAppearance resource.
*/
- public void setSubtitleTextAppearance(Context context, int resId) {
+ public void setSubtitleTextAppearance(Context context, @StyleRes int resId) {
mSubtitleTextAppearance = resId;
if (mSubtitleTextView != null) {
mSubtitleTextView.setTextAppearance(context, resId);
@@ -675,7 +708,7 @@
*
* @param color The new text color in 0xAARRGGBB format
*/
- public void setTitleTextColor(int color) {
+ public void setTitleTextColor(@ColorInt int color) {
mTitleTextColor = color;
if (mTitleTextView != null) {
mTitleTextView.setTextColor(color);
@@ -687,7 +720,7 @@
*
* @param color The new text color in 0xAARRGGBB format
*/
- public void setSubtitleTextColor(int color) {
+ public void setSubtitleTextColor(@ColorInt int color) {
mSubtitleTextColor = color;
if (mSubtitleTextView != null) {
mSubtitleTextView.setTextColor(color);
@@ -714,7 +747,7 @@
* @param resId Resource ID of a content description string to set, or 0 to
* clear the description
*/
- public void setNavigationContentDescription(int resId) {
+ public void setNavigationContentDescription(@StringRes int resId) {
setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
}
@@ -734,7 +767,7 @@
mNavButtonView.setContentDescription(description);
}
}
-
+
/**
* Set the icon to use for the toolbar's navigation button.
*
@@ -747,7 +780,7 @@
*
* @param resId Resource ID of a drawable to set
*/
- public void setNavigationIcon(int resId) {
+ public void setNavigationIcon(@DrawableRes int resId) {
setNavigationIcon(mTintManager.getDrawable(resId));
}
@@ -766,12 +799,12 @@
public void setNavigationIcon(@Nullable Drawable icon) {
if (icon != null) {
ensureNavButtonView();
- if (mNavButtonView.getParent() == null) {
- addSystemView(mNavButtonView);
- updateChildVisibilityForExpandedActionView(mNavButtonView);
+ if (!isChildOrHidden(mNavButtonView)) {
+ addSystemView(mNavButtonView, true);
}
- } else if (mNavButtonView != null && mNavButtonView.getParent() != null) {
+ } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) {
removeView(mNavButtonView);
+ mHiddenViews.remove(mNavButtonView);
}
if (mNavButtonView != null) {
mNavButtonView.setImageDrawable(icon);
@@ -815,6 +848,27 @@
return mMenuView.getMenu();
}
+ /**
+ * Set the icon to use for the overflow button.
+ *
+ * @param icon Drawable to set, may be null to clear the icon
+ */
+ public void setOverflowIcon(@Nullable Drawable icon) {
+ ensureMenu();
+ mMenuView.setOverflowIcon(icon);
+ }
+
+ /**
+ * Return the current drawable used as the overflow icon.
+ *
+ * @return The overflow icon drawable
+ */
+ @Nullable
+ public Drawable getOverflowIcon() {
+ ensureMenu();
+ return mMenuView.getOverflowIcon();
+ }
+
private void ensureMenu() {
ensureMenuView();
if (mMenuView.peekMenu() == null) {
@@ -837,7 +891,7 @@
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = GravityCompat.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mMenuView.setLayoutParams(lp);
- addSystemView(mMenuView);
+ addSystemView(mMenuView, false);
}
}
@@ -853,7 +907,7 @@
*
* @param resId ID of a menu resource to inflate
*/
- public void inflateMenu(int resId) {
+ public void inflateMenu(@MenuRes int resId) {
getMenuInflater().inflate(resId, getMenu());
}
@@ -1014,7 +1068,7 @@
}
}
- private void addSystemView(View v) {
+ private void addSystemView(View v, boolean allowHide) {
final ViewGroup.LayoutParams vlp = v.getLayoutParams();
final LayoutParams lp;
if (vlp == null) {
@@ -1025,7 +1079,13 @@
lp = (LayoutParams) vlp;
}
lp.mViewType = LayoutParams.SYSTEM;
- addView(v, lp);
+
+ if (allowHide && mExpandedActionView != null) {
+ v.setLayoutParams(lp);
+ mHiddenViews.add(v);
+ } else {
+ addView(v, lp);
+ }
}
@Override
@@ -1729,22 +1789,30 @@
return mWrapper;
}
- private void setChildVisibilityForExpandedActionView(boolean expand) {
+ void removeChildrenForExpandedActionView() {
final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
+ // Go backwards since we're removing from the list
+ for (int i = childCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
- child.setVisibility(expand ? GONE : VISIBLE);
+ removeViewAt(i);
+ mHiddenViews.add(child);
}
}
}
- private void updateChildVisibilityForExpandedActionView(View child) {
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
- child.setVisibility(mExpandedActionView != null ? GONE : VISIBLE);
+ void addChildrenForExpandedActionView() {
+ final int count = mHiddenViews.size();
+ // Re-add in reverse order since we removed in reverse order
+ for (int i = count - 1; i >= 0; i--) {
+ addView(mHiddenViews.get(i));
}
+ mHiddenViews.clear();
+ }
+
+ private boolean isChildOrHidden(View child) {
+ return child.getParent() == this || mHiddenViews.contains(child);
}
/**
@@ -1797,7 +1865,7 @@
int mViewType = CUSTOM;
- public LayoutParams(Context c, AttributeSet attrs) {
+ public LayoutParams(@NonNull Context c, AttributeSet attrs) {
super(c, attrs);
}
@@ -1954,7 +2022,7 @@
addView(mExpandedActionView);
}
- setChildVisibilityForExpandedActionView(true);
+ removeChildrenForExpandedActionView();
requestLayout();
item.setActionViewExpanded(true);
@@ -1977,7 +2045,7 @@
removeView(mCollapseButtonView);
mExpandedActionView = null;
- setChildVisibilityForExpandedActionView(false);
+ addChildrenForExpandedActionView();
mCurrentExpandedItem = null;
requestLayout();
item.setActionViewExpanded(false);
diff --git a/v7/gridlayout/tests/src/android/support/v7/widget/test/GridLayoutTest.java b/v7/gridlayout/tests/src/android/support/v7/widget/test/GridLayoutTest.java
index 3a3d10a..1a88be5 100644
--- a/v7/gridlayout/tests/src/android/support/v7/widget/test/GridLayoutTest.java
+++ b/v7/gridlayout/tests/src/android/support/v7/widget/test/GridLayoutTest.java
@@ -20,7 +20,7 @@
import android.os.Debug;
import android.support.v7.widget.GridLayout;
import android.test.ActivityInstrumentationTestCase2;
-import android.support.v7.gridlayout.test.R;
+import android.support.v7.gridlayout.R;
import android.test.UiThreadTest;
import android.view.Gravity;
import android.view.View;
diff --git a/v7/mediarouter/api/current.txt b/v7/mediarouter/api/current.txt
index a382a89..4f2963c 100644
--- a/v7/mediarouter/api/current.txt
+++ b/v7/mediarouter/api/current.txt
@@ -20,6 +20,7 @@
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
method public void setDialogFactory(android.support.v7.app.MediaRouteDialogFactory);
+ method public void setRemoteIndicatorDrawable(android.graphics.drawable.Drawable);
method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
method public boolean showDialog();
}
@@ -41,7 +42,7 @@
method public void setRouteSelector(android.support.v7.media.MediaRouteSelector);
}
- public class MediaRouteControllerDialog extends android.app.Dialog {
+ public class MediaRouteControllerDialog extends android.app.AlertDialog {
ctor public MediaRouteControllerDialog(android.content.Context);
ctor public MediaRouteControllerDialog(android.content.Context, int);
method public android.view.View getMediaControlView();
diff --git a/v7/mediarouter/res/drawable-hdpi/mr_ic_audio_vol.png b/v7/mediarouter/res/drawable-hdpi/mr_ic_audio_vol.png
deleted file mode 100644
index 17565c5..0000000
--- a/v7/mediarouter/res/drawable-hdpi/mr_ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/mr_ic_audio_vol.png b/v7/mediarouter/res/drawable-mdpi/mr_ic_audio_vol.png
deleted file mode 100644
index 36f079d..0000000
--- a/v7/mediarouter/res/drawable-mdpi/mr_ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/mr_ic_audio_vol.png b/v7/mediarouter/res/drawable-xhdpi/mr_ic_audio_vol.png
deleted file mode 100644
index e0dff4c..0000000
--- a/v7/mediarouter/res/drawable-xhdpi/mr_ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/mr_ic_audio_vol.png b/v7/mediarouter/res/drawable-xxhdpi/mr_ic_audio_vol.png
deleted file mode 100755
index 3dd7a68..0000000
--- a/v7/mediarouter/res/drawable-xxhdpi/mr_ic_audio_vol.png
+++ /dev/null
Binary files differ
diff --git a/v7/mediarouter/res/drawable/mr_ic_cast_dark.xml b/v7/mediarouter/res/drawable/mr_ic_cast_dark.xml
new file mode 100644
index 0000000..eaaf9c9
--- /dev/null
+++ b/v7/mediarouter/res/drawable/mr_ic_cast_dark.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_cast_dark" />
+</selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_cast_light.xml b/v7/mediarouter/res/drawable/mr_ic_cast_light.xml
new file mode 100644
index 0000000..342c59e
--- /dev/null
+++ b/v7/mediarouter/res/drawable/mr_ic_cast_light.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_cast_light" />
+</selector>
diff --git a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
index 9482642..3c5ffc9 100644
--- a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
+++ b/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
@@ -14,126 +14,129 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout android:id="@+id/title_bar"
- android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <TextView android:id="@+id/route_name"
- android:layout_width="0dp"
- android:layout_height="72dp"
- android:layout_weight="1"
- android:layout_marginLeft="24dip"
- android:layout_marginRight="24dip"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="?android:attr/textColorPrimary" />
- <ImageButton android:id="@+id/settings"
- android:layout_width="48dip"
- android:layout_height="48dip"
- android:padding="12dip"
- android:layout_marginTop="12dip"
- android:layout_marginBottom="12dip"
- android:layout_marginRight="12dip"
- android:contentDescription="@string/mr_media_route_controller_settings_description"
- android:src="?attr/mediaRouteSettingsDrawable"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:visibility="gone" />
- </LinearLayout>
- <FrameLayout android:id="@+id/media_route_control_frame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
- <RelativeLayout android:id="@+id/default_control_frame"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="?attr/colorPrimary" >
- <ImageView android:id="@+id/art"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:maxHeight="@dimen/mr_media_route_controller_art_max_height"
- android:adjustViewBounds="true"
- android:scaleType="centerCrop"/>
- <ImageButton android:id="@+id/play_pause"
+ android:orientation="horizontal" >
+ <TextView android:id="@+id/route_name"
+ android:layout_width="0dp"
+ android:layout_height="72dp"
+ android:layout_weight="1"
+ android:layout_marginLeft="24dip"
+ android:layout_marginRight="24dip"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary" />
+ <ImageButton android:id="@+id/settings"
android:layout_width="48dip"
android:layout_height="48dip"
android:padding="12dip"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- android:layout_alignParentRight="true"
- android:layout_below="@id/art"
- android:contentDescription="@string/mr_media_route_controller_play"
- android:background="?attr/selectableItemBackgroundBorderless"/>
- <LinearLayout android:id="@+id/text_wrapper"
- android:orientation="vertical"
+ android:layout_marginTop="12dip"
+ android:layout_marginBottom="12dip"
+ android:layout_marginRight="12dip"
+ android:contentDescription="@string/mr_media_route_controller_settings_description"
+ android:src="?attr/mediaRouteSettingsDrawable"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:visibility="gone" />
+ </LinearLayout>
+ <FrameLayout android:id="@+id/media_route_control_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <RelativeLayout android:id="@+id/default_control_frame"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:minHeight="64dip"
- android:layout_marginLeft="24dip"
- android:gravity="center_vertical"
- android:layout_toLeftOf="@id/play_pause"
- android:layout_below="@id/art"
- android:layout_alignParentLeft="true" >
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
+ android:background="?attr/colorPrimary" >
+ <ImageView android:id="@+id/art"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- android:textStyle="bold"
- android:singleLine="true" />
- <TextView android:id="@+id/subtitle"
- android:layout_width="wrap_content"
+ android:maxHeight="@dimen/mr_media_route_controller_art_max_height"
+ android:adjustViewBounds="true"
+ android:scaleType="centerCrop"/>
+ <ImageButton android:id="@+id/play_pause"
+ android:layout_width="48dip"
+ android:layout_height="48dip"
+ android:padding="12dip"
+ android:layout_marginTop="8dip"
+ android:layout_marginBottom="8dip"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/art"
+ android:contentDescription="@string/mr_media_route_controller_play"
+ android:background="?attr/selectableItemBackgroundBorderless"/>
+ <LinearLayout android:id="@+id/text_wrapper"
+ android:orientation="vertical"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp"
- android:singleLine="true" />
- </LinearLayout>
- </RelativeLayout>
- </FrameLayout>
- <!-- Optional volume slider section. -->
- <LinearLayout android:id="@+id/media_route_volume_layout"
- android:layout_width="fill_parent"
- android:layout_height="64dp"
- android:gravity="center_vertical"
- android:padding="8dp"
- android:visibility="gone">
- <ImageView android:layout_width="48dp"
- android:layout_height="48dp"
- android:src="@drawable/mr_ic_audio_vol"
- android:gravity="center"
- android:scaleType="center" />
- <SeekBar android:id="@+id/media_route_volume_slider"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp" />
+ android:layout_width="wrap_content"
+ android:minHeight="64dip"
+ android:layout_marginLeft="24dip"
+ android:gravity="center_vertical"
+ android:layout_toLeftOf="@id/play_pause"
+ android:layout_below="@id/art"
+ android:layout_alignParentLeft="true" >
+ <TextView android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp"
+ android:textStyle="bold"
+ android:singleLine="true" />
+ <TextView android:id="@+id/subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp"
+ android:singleLine="true" />
+ </LinearLayout>
+ </RelativeLayout>
+ </FrameLayout>
+ <!-- Optional volume slider section. -->
+ <LinearLayout android:id="@+id/media_route_volume_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ android:gravity="center_vertical"
+ android:padding="8dp"
+ android:visibility="gone">
+ <ImageView android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:src="?attr/mediaRouteCastDrawable"
+ android:gravity="center"
+ android:scaleType="center" />
+ <SeekBar android:id="@+id/media_route_volume_slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <Button android:id="@+id/disconnect"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:gravity="center"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:text="@string/mr_media_route_controller_disconnect"
+ android:visibility="gone" />
+ <Button android:id="@+id/stop"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:gravity="center"
+ android:layout_weight="1"
+ android:textColor="?attr/colorAccent"
+ android:background="?attr/selectableItemBackgroundBorderless"
+ android:text="@string/mr_media_route_controller_stop" />
+ </LinearLayout>
</LinearLayout>
- <LinearLayout android:id="@+id/buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
- <Button android:id="@+id/disconnect"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:layout_weight="1"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:text="@string/mr_media_route_controller_disconnect"
- android:visibility="gone" />
- <Button android:id="@+id/stop"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:gravity="center"
- android:layout_weight="1"
- android:textColor="?attr/colorAccent"
- android:background="?attr/selectableItemBackgroundBorderless"
- android:text="@string/mr_media_route_controller_stop" />
- </LinearLayout>
-</LinearLayout>
+</ScrollView>
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 885af10..0dcfa86 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Stelsel"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Media-uitvoer"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Saai uit"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Koppel aan toestel"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Soek tans vir toestelle…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ontkoppel"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Hou op uitsaai"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Roete-instellings"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Speel"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Laat wag"</string>
</resources>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index 0027737..5d061c9 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ስርዓት"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"መሣሪያዎች"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"የሚዲያ ውፅዓት"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ውሰድ"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ከመሳሪያ ጋር ያገናኙ"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"መሳሪያዎችን በመፈለግ ላይ…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ግንኙነት አቋርጥ"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"መውሰድ አቁም"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"የመንገድ ቅንብሮች"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"አጫውት"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ለአፍታ አቁም"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 9289a35..ac0fb5d 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"المنفذ الإعلامي"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"إرسال"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"الاتصال بجهاز"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"جارٍ البحث عن الأجهزة…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"قطع الاتصال"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"إيقاف الإرسال"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"إعدادات المسار"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"تشغيل"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"إيقاف مؤقت"</string>
</resources>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az-rAZ/strings.xml
new file mode 100644
index 0000000..2f3ff74
--- /dev/null
+++ b/v7/mediarouter/res/values-az-rAZ/strings.xml
@@ -0,0 +1,29 @@
+<?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="5441529851481176817">"Sistem"</string>
+ <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"İştirakçılar"</string>
+ <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Cihaza qoş"</string>
+ <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Cihazları axtarır..."</string>
+ <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Bağlantını kəs"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Yayımı dayandır"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Marşrut parametrləri"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Göstər"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Fasilə ver"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index ff1401e..0918332 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Изходяща мултимедия"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Предаване"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Свързване с устройство"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Търсят се устройства…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Прекратяване на връзката"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Спиране на предаването"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Настройки за маршрута"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Пускане"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Поставяне на пауза"</string>
</resources>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn-rBD/strings.xml
index d0b2c32..de862e5 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn-rBD/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"সিস্টেম"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ডিভাইসগুলি"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"মিডিয়া আউটপুট"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"কাস্ট করুন"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ডিভাইসে সংযোগ করুন"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ডিভাইসগুলি অনুসন্ধান করা হচ্ছে…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"সংযোগ বিচ্ছিন্ন করুন"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"কাস্ট করা বন্ধ করুন"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"সেটিংস রুট করুন"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"চালান"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"বিরাম দিন"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index dd485de..eac6632 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Sortida de contingut multimèdia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emet"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connecta al dispositiu"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"S\'estan cercant dispositius…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconnecta"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Atura l\'emissió"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuració de la ruta"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reprodueix"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Posa en pausa"</string>
</resources>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index 4687100..111c02a 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Zařízení"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Výstup médií"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Odeslat"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Připojení k zařízení"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Vyhledávání zařízení…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Odpojit"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ukončit odesílání"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavení trasy"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Přehrát"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pozastavit"</string>
</resources>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index fd3b0fb..3b4fbf6 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medieudgang"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Opret forbindelse til enheden"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Søger efter enheder..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Afbryd forbindelsen"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop med at caste"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ruteindstillinger"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Afspil"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sæt på pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 9df0ebf..5b8e494 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Geräte"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medienausgabe"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Übertragen"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Mit Gerät verbinden"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Geräte werden gesucht…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Verbindung aufheben"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Übertragung stoppen"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Routingeinstellungen"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Wiedergabe"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index 5a61395..3640111 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Σύστημα"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Συσκευές"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Έξοδος μέσων"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Μετάδοση"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Σύνδεση με τη συσκευή"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Αναζήτηση συσκευών…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Αποσύνδεση"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Διακοπή μετάδοσης"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ρυθμίσεις διαδρομής"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Αναπαραγωγή"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Παύση"</string>
</resources>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..f5a8531
--- /dev/null
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -0,0 +1,29 @@
+<?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="5441529851481176817">"System"</string>
+ <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
+ <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
+ <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
+ <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index b9af4bf..f5a8531 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Media output"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index b9af4bf..f5a8531 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Media output"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connect to device"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Searching for devices…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnect"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stop casting"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route settings"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Play"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index 211b400..e1cf915 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Salida multimedia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar al dispositivo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Detener transmisión"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuración de ruta"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproducir"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
</resources>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index d3a1639..0f2a8ea 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Salida multimedia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Enviar contenido"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar a dispositivo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Dejar de enviar contenido"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ajustes de ruta"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproducir"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
</resources>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et-rEE/strings.xml
index 7dbdf74..ebc63fd 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et-rEE/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Süsteem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Seadmed"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Meediaväljund"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Ülekandmine"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Seadmega ühendamine"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Seadmete otsimine …"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Katkesta ühendus"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Lõpeta ülekanne"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Marsruudi seaded"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Esitamine"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Peatamine"</string>
</resources>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu-rES/strings.xml
index 728672d..d177a55 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu-rES/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Multimedia-irteera"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Igorri"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Konektatu gailura"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Gailuak bilatzen…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Deskonektatu"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Utzi igortzeari"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ibilbidearen ezarpenak"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Erreproduzitu"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausatu"</string>
</resources>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index 2ffed50..e094982 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"سیستم"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"دستگاهها"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"خروجی رسانه"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"فرستادن"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"برقراری ارتباط با دستگاه"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"در حال جستجو برای دستگاهها..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"قطع ارتباط"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"توقف فرستادن"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"تنظیمات مسیر"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"پخش"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"توقف موقت"</string>
</resources>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index 0692c2f..a21dc91 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Järjestelmä"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Laitteet"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Median äänentoisto"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Lähetä"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Yhdistä laitteeseen"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Etsitään laitteita…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Katkaise yhteys"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Lopeta suoratoisto"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Reitin asetukset"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Toista"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Keskeytä"</string>
</resources>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 9fa3c9c..0655526 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Sortie multimédia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Diffuser"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connexion au périphérique"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Recherche d\'appareils en cours…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Déconnecter"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Arrêter la diffusion"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Paramètres de l\'itinéraire"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Lecture"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Suspendre"</string>
</resources>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index 5607a1c..9fce08a 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Sortie multimédia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Caster"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connecter à l\'appareil"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Recherche d\'appareils en cours…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Déconnecter"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Arrêter la diffusion"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Paramètres de l\'itinéraire"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Lecture"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index d700c14..d1d73f9 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Saída multimedia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emitir"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar co dispositivo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Buscando dispositivos…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Parar de emitir"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configuración da ruta"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduce"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
</resources>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000..2002115
--- /dev/null
+++ b/v7/mediarouter/res/values-gu-rIN/strings.xml
@@ -0,0 +1,29 @@
+<?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="5441529851481176817">"સિસ્ટમ"</string>
+ <string name="mr_user_route_category_name" msgid="7498112907524977311">"ઉપકરણો"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"કાસ્ટ કરો"</string>
+ <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ઉપકરણ સાથે કનેક્ટ કરો"</string>
+ <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ઉપકરણો માટે શોધી રહ્યું છે…"</string>
+ <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ડિસ્કનેક્ટ કરો"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"કાસ્ટ કરવાનું રોકો"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"રૂટ સેટિંગ્સ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ચલાવો"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"થોભો"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index 8acc2bb..6d100ea 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -17,9 +17,13 @@
<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="5441529851481176817">"सिस्टम"</string>
- <string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरण"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"मीडिया आउटपुट"</string>
- <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"उपकरण से कनेक्ट करें"</string>
- <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"उपकरणों की खोज हो रही है…"</string>
+ <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट करें"</string>
+ <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"डिवाइस से कनेक्ट करें"</string>
+ <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"डिवाइस की खोज हो रही है…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"डिस्कनेक्ट करें"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्ट करना बंद करें"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिंग"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"चलाएं"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"रोकें"</string>
</resources>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 2946433..74e9270 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sustav"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medijski izlaz"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Emitiranje"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Povezivanje s uređajem"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Traženje uređaja…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Prekini vezu"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zaustavi emitiranje"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Postavke rute"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reprodukcija"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pauziraj"</string>
</resources>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index b68fe16..efbc193 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Rendszer"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Eszközök"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Médiakimenet"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Tartalomátküldés"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Csatlakozás adott eszközhöz"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Eszközkeresés…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Leválasztás"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Átküldés leállítása"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Útvonal-beállítások"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Indítás"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Szüneteltetés"</string>
</resources>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy-rAM/strings.xml
index 77f1136..faa6020 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy-rAM/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Համակարգ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Սարքեր"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Մեդիա արտածում"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Հեռարձակում"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Միանալ սարքին"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Որոնվում են սարքեր..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Անջատել"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Դադարեցնել հեռարձակումը"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ֆայլերի փոխանցման կարգավորումներ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Նվագարկել"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Դադար"</string>
</resources>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index 1d3b387..e3123c1 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Keluaran media"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmisi"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Sambungkan ke perangkat"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Menelusuri perangkat…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Putuskan sambungan"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Hentikan transmisi"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Setelan rute"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Putar"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Jeda"</string>
</resources>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is-rIS/strings.xml
index 45d7329..262e4e9 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is-rIS/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Kerfi"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Tæki"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Margmiðlunarúttak"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Senda út"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Tengjast tæki"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Leitar að tækjum…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Aftengja"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stöðva útsendingu"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Leiðarstillingar"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spila"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Hlé"</string>
</resources>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index bd58755..bedd617 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivi"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Uscita media"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Trasmetti"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Connetti al dispositivo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Ricerca di dispositivi…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Disconnetti"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interrompi trasmissione"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Impostazioni percorso"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Riproduci"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
</resources>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 59753b4..12d17b9 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"מערכת"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"מכשירים"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"פלט מדיה"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"העבר"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"התחבר למכשיר"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"מחפש מכשירים…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"התנתק"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"עצור העברה"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"הגדרות נתיב"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"הפעל"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"השהה"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index 1367489..e97a65a 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"システム"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"端末"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"メディア出力"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"キャスト"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"端末に接続"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"端末を検索しています…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"接続を解除"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"キャストを停止"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ルーティング設定"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"再生"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"一時停止"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka-rGE/strings.xml
index 413257e..758fe73 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka-rGE/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"სისტემა"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"მოწყობილობები"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"მედია გამოსასვლელი"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"მსახიობები"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"მოწყობილობასთან დაკავშირება"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"მოწყობილობების ძიება…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"კავშირის გაწყვეტა"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ტრანსლაციის შეჩერება"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"მარშრუტის პარამეტრები"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"დაკვრა"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"პაუზა"</string>
</resources>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk-rKZ/strings.xml
index e8da02a..c549a8c 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk-rKZ/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Жүйе"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Құрылғылар"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Meдиа құрылғылары"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Трансляциялау"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Құрылғыға жалғау"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Құрылғыларды іздеуде…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ажырату"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Трансляциялауды тоқтату"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Жол параметрлері"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ойнату"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Кідірту"</string>
</resources>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km-rKH/strings.xml
index e001dde..b3e53c5 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km-rKH/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ប្រព័ន្ធ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ឧបករណ៍"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"លទ្ធផលមេឌៀ"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"បញ្ជូន"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ភ្ជាប់ឧបករណ៍"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"កំពុងស្វែងរកឧបករណ៍..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ផ្ដាច់"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"បញ្ឈប់ការខាស"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ការកំណត់ផ្លូវ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ចាក់"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ផ្អាក"</string>
</resources>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn-rIN/strings.xml
index 147ebc8..36c3aaa 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn-rIN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ಸಿಸ್ಟಂ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ಸಾಧನಗಳು"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"ಮಾಧ್ಯಮ ಔಟ್ಪುಟ್"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ಪಾತ್ರ"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಿ"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ಬಿತ್ತರಿಸುವಿಕೆ ನಿಲ್ಲಿಸು"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ಮಾರ್ಗ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ಪ್ಲೇ ಮಾಡು"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ವಿರಾಮ"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index 21f82a0..d165e52 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"시스템"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"기기"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"미디어 출력"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"전송"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"기기에 연결"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"기기 검색 중…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"연결 해제"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"전송 중지"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"경로 설정"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"재생"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"일시중지"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky-rKG/strings.xml
index 4a587ac..1f7aba0 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky-rKG/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Түзмөктөр"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Медиа чыгаруу"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Тандалгандар"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Түзмөккө туташуу"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Түзмөктөр изделүүдө..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ажыратуу"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Тышк экранга чыгарну токтотуу"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Багыт жөндөөлөрү"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ойнотуу"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Тындыруу"</string>
</resources>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo-rLA/strings.xml
index 31a03cd..6d61f7d 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo-rLA/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ລະບົບ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ອຸປະກອນ"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"ມີເດຍເອົ້າພຸດ"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ສົ່ງສັນຍານ"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ກຳລັງຊອກຫາອຸປະກອນ..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ຕັດການເຊື່ອມຕໍ່"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ຢຸດການສົ່ງສັນຍານ"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ການຕັ້ງຄ່າເສັ້ນທາງ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ຫຼິ້ນ"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ຢຸດຊົ່ວຄາວ"</string>
</resources>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index ead3b73..2315618 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Įrenginiai"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medijos išvestis"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Perduoti"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Prijungimas prie įrenginio"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Ieškoma įrenginių…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Atjungti"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Sustabdyti perdavimą"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Maršruto nustatymai"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Leisti"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pristabdyti"</string>
</resources>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index 0914990..93e45de 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistēma"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Ierīces"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Multivides izeja"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Apraidīt"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Savienojuma izveide ar ierīci"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Notiek ierīču meklēšana..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Atvienot"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Pārtraukt apraidi"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Maršruta iestatījumi"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Atskaņot"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Apturēt"</string>
</resources>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk-rMK/strings.xml
index 363f16b..9b3f875 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk-rMK/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Уреди"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Излез за медиум"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Емитувај"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Поврзи се со уредот"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Се пребаруваат уреди..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Исклучи се"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Запри префрлување"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Поставки на маршрутата"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Репродуцирај"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Пауза"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml-rIN/strings.xml
index d20ba1d..64c74b1 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml-rIN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"മീഡിയ ഔട്ട്പുട്ട്"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"കാസ്റ്റുചെയ്യുക"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ഉപകരണത്തിലേക്ക് കണക്റ്റുചെയ്യുക"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ഉപകരണങ്ങൾക്കായി തിരയുന്നു…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"വിച്ഛേദിക്കുക"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"റൂട്ട് ക്രമീകരണം"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"പ്ലേ ചെയ്യുക"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"താൽക്കാലികമായി നിർത്തുക"</string>
</resources>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn-rMN/strings.xml
index 4eecdb4..2074767 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn-rMN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Төхөөрөмжүүд"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Медиа гаралт"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Дамжуулах"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Төхөөрөмжтэй холбох"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Төхөөрөмжүүдийг хайж байна…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Салгах"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Нэвтрүүлэхийг зогсоох"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Маршрут тохиргоо"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Тоглуулах"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Түр зогсоох"</string>
</resources>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr-rIN/strings.xml
index 9187b5d..bd020a7 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr-rIN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"माध्यम आउटपुट"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट करा"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"डिव्हाइसला कनेक्ट करा"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"डिव्हाइसेस शोधत आहे…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"डिस्कनेक्ट करा"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्ट करणे थांबवा"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिंग्ज"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"प्ले करा"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"विराम द्या"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms-rMY/strings.xml
index dadaa30..05e9ffa 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms-rMY/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Peranti"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Output media"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Barisan pelakon"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Sambung kepada peranti"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Mencari peranti..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Putuskan sambungan"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Berhenti menghantar"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Tetapan laluan"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Main"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Jeda"</string>
</resources>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my-rMM/strings.xml
index c417d57..20bfd8d 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my-rMM/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"စနစ်"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"စက်ပစ္စည်းများ"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"မီဒီယာထွက်ပေါက်"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"သရုပ်ဆောင်များ"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"စက်တစ်ခုကို ချိတ်ဆက်ပါ"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"စက်ပစ္စည်းများကို ရှာဖွေနေပါသည်"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ချိတ်ဆက်ခြင်းရပ်တန့်ရန်"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ပုံစံသွင်းမှု ရပ်ရန်"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"လမ်းကြောင်း အပြင်အဆင်များ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ဖွင့်ရန်"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ခဏရပ်ရန်"</string>
</resources>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index fa4d9a4..5ee8ec8 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medieutgang"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Koble til enheten"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Søker etter enheter …"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Koble fra"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Stopp castingen"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ruteinnstillinger"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spill av"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sett på pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne-rNP/strings.xml
index 3fe9ac3..aadcbcf 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne-rNP/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"प्रणाली"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरणहरू"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"मिडियाको उत्पादन"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"कास्ट"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"उपकरणसँग जडान गर्नुहोस्"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"उपकरणहरूका लागि खोजी गरिँदै..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"विच्छेदन गर्नुहोस्"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"कास्टिंग रोक्नुहोस्"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"मार्ग सेटिङ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"बजाउनुहोस्"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"रोक्नुहोस्"</string>
</resources>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index 5572449..fcfac4d 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Systeem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Media-uitvoer"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Casten"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Verbinding maken met apparaat"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Zoeken naar apparaten…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Verbinding verbreken"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Casten stoppen"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Route-instellingen"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Afspelen"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Onderbreken"</string>
</resources>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000..fb87320
--- /dev/null
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -0,0 +1,29 @@
+<?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="5441529851481176817">"ਸਿਸਟਮ"</string>
+ <string name="mr_user_route_category_name" msgid="7498112907524977311">"ਡਿਵਾਈਸਾਂ"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ਜੋੜੋ"</string>
+ <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"ਡਿਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"ਡਿਵਾਈਸਾਂ ਦੀ ਖੋਜ ਕਰ ਰਿਹਾ ਹੈ…"</string>
+ <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ਜੋੜਨਾ ਰੋਕੋ"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ਰੂਟ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ਪਲੇ ਕਰੋ"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"ਰੋਕੋ"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index 95a1d03..34fea86 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Urządzenia"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Wyjście multimediów"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Przesyłaj"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Połącz z urządzeniem"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Szukam urządzeń…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Rozłącz"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zakończ przesyłanie"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Ustawienia trasy"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Odtwórz"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Wstrzymaj"</string>
</resources>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index 54b1dfc..1e1dbbb 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Saída de som multimédia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Ligar ao dispositivo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"A pesquisar dispositivos…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desassociar"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Parar a transmissão"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Definições de trajeto"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Colocar em pausa"</string>
</resources>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index 3ce1c38..67648a7 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Saída de mídia"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmitir"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectar ao dispositivo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Procurando dispositivos…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Desconectar"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Interromper transmissão"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Configurações de rota"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Reproduzir"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausar"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index 4c9e4b9..d738bab 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispozitive"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Rezultate media"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Trimiteți"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Conectați-vă la dispozitiv"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Se caută dispozitive..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Deconectați-vă"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Nu mai proiectați"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Setări pentru traseu"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Redați"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Întrerupeți"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 5cc2bba..dfa836c 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Перенаправлять поток мультимедиа"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Транслировать."</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Подключение к устройству"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Поиск устройств…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Отключить"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Остановить трансляцию"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Настройки передачи файлов"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Воспроизвести."</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Приостановить."</string>
</resources>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si-rLK/strings.xml
index 2eba3c8..1ac7319 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si-rLK/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"පද්ධතිය"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"උපාංග"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"මාධ්ය ප්රතිදානය"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Cast"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"උපාංගයට සම්බන්ධ වන්න"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"උපාංග සඳහා සොයමින්…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"විසන්ධි කරන්න"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"කාස්ට් කිරීම නවත්වන්න"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"ගමන් මගේ සැකසීම්"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ධාවනය කරන්න"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"විරාමය"</string>
</resources>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index 668800f..3156edf 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Zariadenia"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Výstup médií"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Preniesť"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Pripojenie k zariadeniu"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Prebieha vyhľadávanie zariadení…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Odpojiť"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Zastaviť prenášanie"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavenia trasy"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Prehrať"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pozastaviť"</string>
</resources>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index 3e3e8bb..3de14aa 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Naprave"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Izhod za predstavnost"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Predvajanje"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Povezovanje z napravo"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Iskanje naprav …"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Prekini povezavo"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ustavi predvajanje"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Nastavitve poti"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Predvajaj"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Zaustavi"</string>
</resources>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq-rAL/strings.xml
new file mode 100644
index 0000000..2df43b1
--- /dev/null
+++ b/v7/mediarouter/res/values-sq-rAL/strings.xml
@@ -0,0 +1,29 @@
+<?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="5441529851481176817">"Sistemi"</string>
+ <string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Transmeto"</string>
+ <string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Lidhu me pajisjen"</string>
+ <string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Po kërkon për pajisje…"</string>
+ <string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Shkëputu"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ndalo transmetimin"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Cilësimet e rrugës"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Luaj"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pauzë"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 320f3e8..de10685 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Уређаји"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Излаз медија"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Пребацуј"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Повежите са уређајем"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Претраживање уређаја…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Прекини везу"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Заустави пребацивање"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Подешавања путање"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Пусти"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Паузирај"</string>
</resources>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 910c6f1..3ac428a 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medieuppspelning"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Casta"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Anslut till enhet"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Söker efter enheter ..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Koppla från"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Sluta casta"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Inställningar för omdirigering"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Spela upp"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Pausa"</string>
</resources>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index fcbc590..00ce337 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Mfumo"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Towe la vyombo vya habari"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Tuma"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Unganisha kwenye kifaa"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Inatafuta vifaa..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Tenganisha"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Acha kutuma"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Mipangilio ya njia"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Google Play"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Sitisha"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta-rIN/strings.xml
index d5d1386..f92c432 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta-rIN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"மீடியா வெளியீடு"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"அனுப்பு"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"சாதனத்துடன் இணைக்கவும்"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"சாதனங்களைத் தேடுகிறது..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"துண்டி"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"அனுப்புவதை நிறுத்து"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"வழி அமைப்புகள்"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"இயக்கு"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"இடைநிறுத்து"</string>
</resources>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te-rIN/strings.xml
index 9fa6e90..0913420 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te-rIN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"సిస్టమ్"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"పరికరాలు"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"మీడియా అవుట్పుట్"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ప్రసారం చేయండి"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"పరికరానికి కనెక్ట్ చేయండి"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"పరికరాల కోసం శోధిస్తోంది…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"డిస్కనెక్ట్ చేయి"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"ప్రసారాన్ని ఆపివేయి"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"మార్గ సెట్టింగ్లు"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"ప్లే చేయి"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"పాజ్ చేయి"</string>
</resources>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 78e5a73..31fc9c7 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"ระบบ"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"อุปกรณ์"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"เอาต์พุตสื่อ"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"ส่ง"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"เชื่อมต่อกับอุปกรณ์"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"กำลังค้นหาอุปกรณ์…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"ยกเลิกการเชื่อมต่อ"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"หยุดการส่ง"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"การตั้งค่าเส้นทาง"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"เล่น"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"หยุดชั่วคราว"</string>
</resources>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index 0953787..d4896b5 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Mga Device"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Output ng media"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"I-cast"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Kumonekta sa device"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Naghahanap ng mga device…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Idiskonekta"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Itigil ang pagca-cast"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Mga setting ng ruta"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"I-play"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"I-pause"</string>
</resources>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index 12faaa6..05344ff 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Medya çıkışı"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Yayınla"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Cihaza bağlanın"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Cihaz arayın…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Bağlantıyı kes"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Yayını durdur"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Rota ayarları"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Oynat"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Duraklat"</string>
</resources>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index b036dea..b445b9c 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Пристрої"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Вивід медіа-даних"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Транслювати"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Під’єднатися до пристрою"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Пошук пристроїв…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Від’єднатися"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Зупинити трансляцію"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Налаштування маршруту"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Відтворити"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Призупинити"</string>
</resources>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur-rPK/strings.xml
index bce0e0c..e6ce4d6 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur-rPK/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"سسٹم"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"آلات"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"میڈیا آؤٹ پٹ"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"کاسٹ کریں"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"آلہ سے مربوط ہوں"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"آلات تلاش کر رہا ہے…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"غیر مربوط کریں"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"کاسٹ کرنا بند کریں"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"روٹ کی ترتیبات"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"چلائیں"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"موقوف کریں"</string>
</resources>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz-rUZ/strings.xml
index f191fd9..d2829ee 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz-rUZ/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Tizim"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Media chiqish"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Translatsiya qilish"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Qurilmaga ulanish"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Qurilmalar izlanmoqda…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Uzish"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Translatsiyani to‘xtatish"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Yo‘naltirish sozlamalari"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Ijro qilish"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"To‘xtatib turish"</string>
</resources>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index a58d0e4..01ec106 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Hệ thống"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Thiết bị"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Đầu ra phương tiện"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Truyền"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Kết nối với thiết bị"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Đang tìm kiếm thiết bị…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Ngắt kết nối"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Ngừng truyền"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Cài đặt tuyến đường"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Phát"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Tạm dừng"</string>
</resources>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index 71c4407..070f1de 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"系统"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"设备"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"媒体输出线路"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投射"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"连接到设备"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜索设备…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"断开连接"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投射"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由设置"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暂停"</string>
</resources>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index f499169..a73d636 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"媒體輸出"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投放"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"連線至裝置"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜尋裝置…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"中斷連線"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投放"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由設定"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暫停"</string>
</resources>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index a847615..cb07c25 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"媒體輸出"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"投放"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"連線至裝置"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"正在搜尋裝置..."</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"中斷連線"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"停止投放"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"路由設定"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"播放"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"暫停"</string>
</resources>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index be195be..24f0a37 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -18,8 +18,12 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mr_system_route_name" msgid="5441529851481176817">"Isistimu"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
- <string name="mr_media_route_button_content_description" msgid="4271159405637008602">"Okukhiphayo kwabezindaba"</string>
+ <string name="mr_media_route_button_content_description" msgid="8327680881775995150">"Abalingisi"</string>
<string name="mr_media_route_chooser_title" msgid="7106830097177242655">"Xhumeka kudivayisi"</string>
<string name="mr_media_route_chooser_searching" msgid="7553005460920830010">"Iseshela amadivayisi…"</string>
<string name="mr_media_route_controller_disconnect" msgid="109793632378378069">"Nqamula"</string>
+ <string name="mr_media_route_controller_stop" msgid="5398645111664294430">"Misa ukusakaza"</string>
+ <string name="mr_media_route_controller_settings_description" msgid="379358765881274425">"Izilungiselelo zomzila"</string>
+ <string name="mr_media_route_controller_play" msgid="5214423499524760404">"Dlala"</string>
+ <string name="mr_media_route_controller_pause" msgid="8315773974194466049">"Misa isikhashana"</string>
</resources>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index 5cd5606..9f5f8ac 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -33,4 +33,5 @@
<attr name="mediaRouteSettingsDrawable" format="reference" />
<attr name="mediaRoutePlayDrawable" format="reference" />
<attr name="mediaRoutePauseDrawable" format="reference" />
+ <attr name="mediaRouteCastDrawable" format="reference" />
</resources>
\ No newline at end of file
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/res/values/themes.xml
index 8350e04..85d0a8b 100644
--- a/v7/mediarouter/res/values/themes.xml
+++ b/v7/mediarouter/res/values/themes.xml
@@ -25,6 +25,7 @@
<item name="mediaRouteSettingsDrawable">@drawable/mr_ic_settings_dark</item>
<item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_dark</item>
<item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_dark</item>
+ <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_dark</item>
</style>
<style name="Theme.MediaRouter.Light" parent="">
@@ -36,6 +37,7 @@
<item name="mediaRouteSettingsDrawable">@drawable/mr_ic_settings_light</item>
<item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_light</item>
<item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_light</item>
+ <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_light</item>
</style>
</resources>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
index 896c116..8a5f507 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
@@ -356,7 +356,10 @@
}
}
- private void setRemoteIndicatorDrawable(Drawable d) {
+ /**
+ * Sets a drawable to use as the remote route indicator.
+ */
+ public void setRemoteIndicatorDrawable(Drawable d) {
if (mRemoteIndicator != null) {
mRemoteIndicator.setCallback(null);
unscheduleDrawable(mRemoteIndicator);
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index 3312f7f..87bc7f6 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -16,7 +16,7 @@
package android.support.v7.app;
-import android.app.Dialog;
+import android.app.AlertDialog;
import android.content.Context;
import android.content.IntentSender;
import android.graphics.drawable.Drawable;
@@ -34,7 +34,6 @@
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
-import android.view.Window;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
@@ -52,7 +51,7 @@
* @see MediaRouteButton
* @see MediaRouteActionProvider
*/
-public class MediaRouteControllerDialog extends Dialog {
+public class MediaRouteControllerDialog extends AlertDialog {
private static final String TAG = "MediaRouteControllerDialog";
// Time to wait before updating the volume when the user lets go of the seek bar
@@ -206,8 +205,6 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-
setContentView(R.layout.mr_media_route_controller_material_dialog_b);
ClickListener listener = new ClickListener();
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index c3f3e78..1ffb7a1 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -19,6 +19,8 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.AsyncTask;
+import android.support.annotation.ColorInt;
+import android.support.annotation.Nullable;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.os.AsyncTaskCompat;
import android.util.TimingLogger;
@@ -153,6 +155,7 @@
/**
* Returns the most vibrant swatch in the palette. Might be null.
*/
+ @Nullable
public Swatch getVibrantSwatch() {
return mGenerator.getVibrantSwatch();
}
@@ -160,6 +163,7 @@
/**
* Returns a light and vibrant swatch from the palette. Might be null.
*/
+ @Nullable
public Swatch getLightVibrantSwatch() {
return mGenerator.getLightVibrantSwatch();
}
@@ -167,6 +171,7 @@
/**
* Returns a dark and vibrant swatch from the palette. Might be null.
*/
+ @Nullable
public Swatch getDarkVibrantSwatch() {
return mGenerator.getDarkVibrantSwatch();
}
@@ -174,6 +179,7 @@
/**
* Returns a muted swatch from the palette. Might be null.
*/
+ @Nullable
public Swatch getMutedSwatch() {
return mGenerator.getMutedSwatch();
}
@@ -181,6 +187,7 @@
/**
* Returns a muted and light swatch from the palette. Might be null.
*/
+ @Nullable
public Swatch getLightMutedSwatch() {
return mGenerator.getLightMutedSwatch();
}
@@ -188,6 +195,7 @@
/**
* Returns a muted and dark swatch from the palette. Might be null.
*/
+ @Nullable
public Swatch getDarkMutedSwatch() {
return mGenerator.getDarkMutedSwatch();
}
@@ -197,7 +205,8 @@
*
* @param defaultColor value to return if the swatch isn't available
*/
- public int getVibrantColor(int defaultColor) {
+ @ColorInt
+ public int getVibrantColor(@ColorInt int defaultColor) {
Swatch swatch = getVibrantSwatch();
return swatch != null ? swatch.getRgb() : defaultColor;
}
@@ -207,7 +216,8 @@
*
* @param defaultColor value to return if the swatch isn't available
*/
- public int getLightVibrantColor(int defaultColor) {
+ @ColorInt
+ public int getLightVibrantColor(@ColorInt int defaultColor) {
Swatch swatch = getLightVibrantSwatch();
return swatch != null ? swatch.getRgb() : defaultColor;
}
@@ -217,7 +227,8 @@
*
* @param defaultColor value to return if the swatch isn't available
*/
- public int getDarkVibrantColor(int defaultColor) {
+ @ColorInt
+ public int getDarkVibrantColor(@ColorInt int defaultColor) {
Swatch swatch = getDarkVibrantSwatch();
return swatch != null ? swatch.getRgb() : defaultColor;
}
@@ -227,7 +238,8 @@
*
* @param defaultColor value to return if the swatch isn't available
*/
- public int getMutedColor(int defaultColor) {
+ @ColorInt
+ public int getMutedColor(@ColorInt int defaultColor) {
Swatch swatch = getMutedSwatch();
return swatch != null ? swatch.getRgb() : defaultColor;
}
@@ -237,7 +249,8 @@
*
* @param defaultColor value to return if the swatch isn't available
*/
- public int getLightMutedColor(int defaultColor) {
+ @ColorInt
+ public int getLightMutedColor(@ColorInt int defaultColor) {
Swatch swatch = getLightMutedSwatch();
return swatch != null ? swatch.getRgb() : defaultColor;
}
@@ -247,7 +260,8 @@
*
* @param defaultColor value to return if the swatch isn't available
*/
- public int getDarkMutedColor(int defaultColor) {
+ @ColorInt
+ public int getDarkMutedColor(@ColorInt int defaultColor) {
Swatch swatch = getDarkMutedSwatch();
return swatch != null ? swatch.getRgb() : defaultColor;
}
@@ -286,7 +300,7 @@
private float[] mHsl;
- public Swatch(int color, int population) {
+ public Swatch(@ColorInt int color, int population) {
mRed = Color.red(color);
mGreen = Color.green(color);
mBlue = Color.blue(color);
@@ -305,6 +319,7 @@
/**
* @return this swatch's RGB color value
*/
+ @ColorInt
public int getRgb() {
return mRgb;
}
@@ -334,6 +349,7 @@
* Returns an appropriate color to use for any 'title' text which is displayed over this
* {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
*/
+ @ColorInt
public int getTitleTextColor() {
ensureTextColorsGenerated();
return mTitleTextColor;
@@ -343,6 +359,7 @@
* Returns an appropriate color to use for any 'body' text which is displayed over this
* {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
*/
+ @ColorInt
public int getBodyTextColor() {
ensureTextColorsGenerated();
return mBodyTextColor;
diff --git a/v7/preference/Android.mk b/v7/preference/Android.mk
new file mode 100644
index 0000000..e2db0f1
--- /dev/null
+++ b/v7/preference/Android.mk
@@ -0,0 +1,58 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the resources using the current SDK version.
+# We do this here because the final static library must be compiled with an older
+# SDK version than the resources. The resources library and the R class that it
+# contains will not be linked into the final static library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v7-preference-res
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, dummy)
+LOCAL_RESOURCE_DIR := \
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/recyclerview/res \
+ $(LOCAL_PATH)/res
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay
+LOCAL_JAR_EXCLUDE_FILES := none
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Here is the final static library that apps can link against.
+# The R class is automatically excluded from the generated library.
+# Applications that use this library must specify LOCAL_RESOURCE_DIR
+# in their makefiles to include the resources in their package.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-v7-preference
+LOCAL_SDK_VERSION := 7
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+# LOCAL_STATIC_JAVA_LIBRARIES :=
+LOCAL_JAVA_LIBRARIES := \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-recyclerview \
+ android-support-annotations \
+ android-support-v7-preference-res
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# API Check
+# ---------------------------------------------
+support_module := $(LOCAL_MODULE)
+support_module_api_dir := $(LOCAL_PATH)/api
+support_module_src_files := $(LOCAL_SRC_FILES)
+support_module_java_libraries := $(LOCAL_JAVA_LIBRARIES)
+support_module_java_packages := android.support.v7.preference
+include $(SUPPORT_API_CHECK)
diff --git a/v7/preference/AndroidManifest.xml b/v7/preference/AndroidManifest.xml
new file mode 100644
index 0000000..e5aa094
--- /dev/null
+++ b/v7/preference/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.support.v7.preference"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="7" />
+ <application />
+</manifest>
diff --git a/v7/preference/api/current.txt b/v7/preference/api/current.txt
new file mode 100644
index 0000000..a432b43
--- /dev/null
+++ b/v7/preference/api/current.txt
@@ -0,0 +1,318 @@
+package android.support.v7.preference {
+
+ public class CheckBoxPreference extends android.support.v7.preference.TwoStatePreference {
+ ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
+ ctor public CheckBoxPreference(android.content.Context);
+ }
+
+ public abstract class DialogPreference extends android.support.v7.preference.Preference {
+ ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
+ ctor public DialogPreference(android.content.Context);
+ method public android.graphics.drawable.Drawable getDialogIcon();
+ method public int getDialogLayoutResource();
+ method public java.lang.CharSequence getDialogMessage();
+ method public java.lang.CharSequence getDialogTitle();
+ method public java.lang.CharSequence getNegativeButtonText();
+ method public java.lang.CharSequence getPositiveButtonText();
+ method public void setDialogIcon(android.graphics.drawable.Drawable);
+ method public void setDialogIcon(int);
+ method public void setDialogLayoutResource(int);
+ method public void setDialogMessage(java.lang.CharSequence);
+ method public void setDialogMessage(int);
+ method public void setDialogTitle(java.lang.CharSequence);
+ method public void setDialogTitle(int);
+ method public void setNegativeButtonText(java.lang.CharSequence);
+ method public void setNegativeButtonText(int);
+ method public void setPositiveButtonText(java.lang.CharSequence);
+ method public void setPositiveButtonText(int);
+ }
+
+ public static abstract interface DialogPreference.TargetFragment {
+ method public abstract android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ }
+
+ public class EditTextPreference extends android.support.v7.preference.DialogPreference {
+ ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
+ ctor public EditTextPreference(android.content.Context);
+ method public java.lang.String getText();
+ method public void setText(java.lang.String);
+ }
+
+ public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+ ctor public EditTextPreferenceDialogFragmentCompat();
+ method public static android.support.v7.preference.EditTextPreferenceDialogFragmentCompat newInstance(java.lang.String);
+ method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class ListPreference extends android.support.v7.preference.DialogPreference {
+ ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public ListPreference(android.content.Context, android.util.AttributeSet);
+ ctor public ListPreference(android.content.Context);
+ method public int findIndexOfValue(java.lang.String);
+ method public java.lang.CharSequence[] getEntries();
+ method public java.lang.CharSequence getEntry();
+ method public java.lang.CharSequence[] getEntryValues();
+ method public java.lang.String getValue();
+ method public void setEntries(java.lang.CharSequence[]);
+ method public void setEntries(int);
+ method public void setEntryValues(java.lang.CharSequence[]);
+ method public void setEntryValues(int);
+ method public void setValue(java.lang.String);
+ method public void setValueIndex(int);
+ }
+
+ public class ListPreferenceDialogFragmentCompat extends android.support.v7.preference.PreferenceDialogFragmentCompat {
+ ctor public ListPreferenceDialogFragmentCompat();
+ method public static android.support.v7.preference.ListPreferenceDialogFragmentCompat newInstance(java.lang.String);
+ method public void onDialogClosed(boolean);
+ }
+
+ public class Preference {
+ ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public Preference(android.content.Context, android.util.AttributeSet, int);
+ ctor public Preference(android.content.Context, android.util.AttributeSet);
+ ctor public Preference(android.content.Context);
+ method public boolean callChangeListener(java.lang.Object);
+ method public int compareTo(android.support.v7.preference.Preference);
+ method protected android.support.v7.preference.Preference findPreferenceInHierarchy(java.lang.String);
+ method public android.content.Context getContext();
+ method public java.lang.String getDependency();
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getFragment();
+ method public android.graphics.drawable.Drawable getIcon();
+ method public android.content.Intent getIntent();
+ method public java.lang.String getKey();
+ method public final int getLayoutResource();
+ method public android.support.v7.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
+ method public android.support.v7.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
+ method public int getOrder();
+ method protected boolean getPersistedBoolean(boolean);
+ method protected float getPersistedFloat(float);
+ method protected int getPersistedInt(int);
+ method protected long getPersistedLong(long);
+ method protected java.lang.String getPersistedString(java.lang.String);
+ method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+ method public android.content.SharedPreferences getSharedPreferences();
+ method public boolean getShouldDisableView();
+ method public java.lang.CharSequence getSummary();
+ method public java.lang.CharSequence getTitle();
+ method public final int getWidgetLayoutResource();
+ method public boolean hasKey();
+ method public boolean isEnabled();
+ method public boolean isPersistent();
+ method public boolean isSelectable();
+ method public final boolean isVisible();
+ method protected void notifyChanged();
+ method public void notifyDependencyChange(boolean);
+ method protected void notifyHierarchyChanged();
+ method protected void onAttached();
+ method protected void onAttachedToHierarchy(android.support.v7.preference.PreferenceManager);
+ method public void onBindViewHolder(android.support.v7.preference.PreferenceViewHolder);
+ method protected void onClick();
+ method public void onDependencyChanged(android.support.v7.preference.Preference, boolean);
+ method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
+ method public void onParentChanged(android.support.v7.preference.Preference, boolean);
+ method protected void onPrepareForRemoval();
+ method protected void onRestoreInstanceState(android.os.Parcelable);
+ method protected android.os.Parcelable onSaveInstanceState();
+ method protected void onSetInitialValue(boolean, java.lang.Object);
+ method public android.os.Bundle peekExtras();
+ method protected boolean persistBoolean(boolean);
+ method protected boolean persistFloat(float);
+ method protected boolean persistInt(int);
+ method protected boolean persistLong(long);
+ method protected boolean persistString(java.lang.String);
+ method public void restoreHierarchyState(android.os.Bundle);
+ method public void saveHierarchyState(android.os.Bundle);
+ method public void setDefaultValue(java.lang.Object);
+ method public void setDependency(java.lang.String);
+ method public void setEnabled(boolean);
+ method public void setFragment(java.lang.String);
+ method public void setIcon(android.graphics.drawable.Drawable);
+ method public void setIcon(int);
+ method public void setIntent(android.content.Intent);
+ method public void setKey(java.lang.String);
+ method public void setLayoutResource(int);
+ method public void setOnPreferenceChangeListener(android.support.v7.preference.Preference.OnPreferenceChangeListener);
+ method public void setOnPreferenceClickListener(android.support.v7.preference.Preference.OnPreferenceClickListener);
+ method public void setOrder(int);
+ method public void setPersistent(boolean);
+ method public void setSelectable(boolean);
+ method public void setShouldDisableView(boolean);
+ method public void setSummary(java.lang.CharSequence);
+ method public void setSummary(int);
+ method public void setTitle(java.lang.CharSequence);
+ method public void setTitle(int);
+ method public final void setVisible(boolean);
+ method public void setWidgetLayoutResource(int);
+ method public boolean shouldDisableDependents();
+ method protected boolean shouldPersist();
+ field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
+ }
+
+ public static class Preference.BaseSavedState extends android.view.AbsSavedState {
+ ctor public Preference.BaseSavedState(android.os.Parcel);
+ ctor public Preference.BaseSavedState(android.os.Parcelable);
+ field public static final android.os.Parcelable.Creator<android.support.v7.preference.Preference.BaseSavedState> CREATOR;
+ }
+
+ public static abstract interface Preference.OnPreferenceChangeListener {
+ method public abstract boolean onPreferenceChange(android.support.v7.preference.Preference, java.lang.Object);
+ }
+
+ public static abstract interface Preference.OnPreferenceClickListener {
+ method public abstract boolean onPreferenceClick(android.support.v7.preference.Preference);
+ }
+
+ public class PreferenceCategory extends android.support.v7.preference.PreferenceGroup {
+ ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
+ ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
+ ctor public PreferenceCategory(android.content.Context);
+ }
+
+ public abstract class PreferenceDialogFragmentCompat extends android.support.v4.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
+ ctor public PreferenceDialogFragmentCompat();
+ method public android.support.v7.preference.DialogPreference getPreference();
+ method protected void onBindDialogView(android.view.View);
+ method public void onClick(android.content.DialogInterface, int);
+ method protected android.view.View onCreateDialogView(android.content.Context);
+ method public abstract void onDialogClosed(boolean);
+ method protected void onPrepareDialogBuilder(android.support.v7.app.AlertDialog.Builder);
+ field protected static final java.lang.String ARG_KEY = "key";
+ }
+
+ public abstract class PreferenceFragmentCompat extends android.support.v4.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
+ ctor public PreferenceFragmentCompat();
+ method public void addPreferencesFromResource(int);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public final android.support.v7.widget.RecyclerView getListView();
+ method public android.support.v7.preference.PreferenceManager getPreferenceManager();
+ method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+ method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
+ method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
+ method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
+ method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
+ method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+ method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+ method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
+ method public void setPreferencesFromResource(int, java.lang.String);
+ field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+ }
+
+ public static abstract interface PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
+ method public abstract boolean onPreferenceDisplayDialog(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
+ method public abstract boolean onPreferenceStartFragment(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
+ method public abstract boolean onPreferenceStartScreen(android.support.v7.preference.PreferenceFragmentCompat, android.support.v7.preference.PreferenceScreen);
+ }
+
+ public abstract class PreferenceGroup extends android.support.v7.preference.Preference {
+ ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
+ ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
+ method public void addItemFromInflater(android.support.v7.preference.Preference);
+ method public boolean addPreference(android.support.v7.preference.Preference);
+ method protected void dispatchRestoreInstanceState(android.os.Bundle);
+ method protected void dispatchSaveInstanceState(android.os.Bundle);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public android.support.v7.preference.Preference getPreference(int);
+ method public int getPreferenceCount();
+ method protected boolean isOnSameScreenAsChildren();
+ method public boolean isOrderingAsAdded();
+ method protected boolean onPrepareAddPreference(android.support.v7.preference.Preference);
+ method public void removeAll();
+ method public boolean removePreference(android.support.v7.preference.Preference);
+ method public void setOrderingAsAdded(boolean);
+ }
+
+ public class PreferenceManager {
+ method public android.support.v7.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
+ method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
+ method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
+ method public android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
+ method public android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
+ method public android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
+ method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
+ method public android.content.SharedPreferences getSharedPreferences();
+ method public int getSharedPreferencesMode();
+ method public java.lang.String getSharedPreferencesName();
+ method public static void setDefaultValues(android.content.Context, int, boolean);
+ method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+ method public void setOnDisplayPreferenceDialogListener(android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
+ method public void setOnNavigateToScreenListener(android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener);
+ method public void setOnPreferenceTreeClickListener(android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener);
+ method public boolean setPreferences(android.support.v7.preference.PreferenceScreen);
+ method public void setSharedPreferencesMode(int);
+ method public void setSharedPreferencesName(java.lang.String);
+ method public void showDialog(android.support.v7.preference.Preference);
+ field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+ }
+
+ public static abstract interface PreferenceManager.OnDisplayPreferenceDialogListener {
+ method public abstract void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
+ }
+
+ public static abstract interface PreferenceManager.OnNavigateToScreenListener {
+ method public abstract void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
+ }
+
+ public static abstract interface PreferenceManager.OnPreferenceTreeClickListener {
+ method public abstract boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
+ }
+
+ public final class PreferenceScreen extends android.support.v7.preference.PreferenceGroup {
+ }
+
+ public class PreferenceViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
+ method public android.view.View findViewById(int);
+ }
+
+ public class SwitchPreferenceCompat extends android.support.v7.preference.TwoStatePreference {
+ ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet, int);
+ ctor public SwitchPreferenceCompat(android.content.Context, android.util.AttributeSet);
+ ctor public SwitchPreferenceCompat(android.content.Context);
+ method public java.lang.CharSequence getSwitchTextOff();
+ method public java.lang.CharSequence getSwitchTextOn();
+ method public void setSwitchTextOff(java.lang.CharSequence);
+ method public void setSwitchTextOff(int);
+ method public void setSwitchTextOn(java.lang.CharSequence);
+ method public void setSwitchTextOn(int);
+ }
+
+ public abstract class TwoStatePreference extends android.support.v7.preference.Preference {
+ ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
+ ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
+ ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
+ ctor public TwoStatePreference(android.content.Context);
+ method public boolean getDisableDependentsState();
+ method public java.lang.CharSequence getSummaryOff();
+ method public java.lang.CharSequence getSummaryOn();
+ method public boolean isChecked();
+ method public void setChecked(boolean);
+ method public void setDisableDependentsState(boolean);
+ method public void setSummaryOff(java.lang.CharSequence);
+ method public void setSummaryOff(int);
+ method public void setSummaryOn(java.lang.CharSequence);
+ method public void setSummaryOn(int);
+ method protected void syncSummaryView(android.support.v7.preference.PreferenceViewHolder);
+ field protected boolean mChecked;
+ }
+
+}
+
diff --git a/v7/preference/api/removed.txt b/v7/preference/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v7/preference/api/removed.txt
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
new file mode 100644
index 0000000..6576e5f
--- /dev/null
+++ b/v7/preference/build.gradle
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+apply plugin: 'android-library'
+
+archivesBaseName = 'preference-v7'
+
+dependencies {
+ compile project(':support-v4')
+ compile project(':support-appcompat-v7')
+ compile project(':support-recyclerview-v7')
+}
+
+android {
+ compileSdkVersion 'current'
+
+ sourceSets {
+ main.manifest.srcFile 'AndroidManifest.xml'
+ main.java.srcDir 'src'
+ main.res.srcDir 'res'
+ main.assets.srcDir 'assets'
+ main.resources.srcDir 'src'
+
+ // this moves src/instrumentTest to tests so all folders follow:
+ // tests/java, tests/res, tests/assets, ...
+ // This is a *reset* so it replaces the default paths
+ androidTest.setRoot('tests')
+ androidTest.java.srcDir 'tests/src'
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ lintOptions {
+ // TODO: fix errors and reenable.
+ abortOnError false
+ }
+}
diff --git a/v7/preference/res/layout-v11/preference.xml b/v7/preference/res/layout-v11/preference.xml
new file mode 100644
index 0000000..dbf6210
--- /dev/null
+++ b/v7/preference/res/layout-v11/preference.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingEnd="?android:attr/scrollbarSize"
+ android:background="?android:attr/selectableItemBackground"
+ android:focusable="true" >
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+ </FrameLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="15dip"
+ android:layout_marginEnd="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v7/preference/res/layout/preference.xml b/v7/preference/res/layout/preference.xml
new file mode 100644
index 0000000..9f610a3
--- /dev/null
+++ b/v7/preference/res/layout/preference.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingEnd="?android:attr/scrollbarSize"
+ android:background="@android:drawable/list_selector_background"
+ android:focusable="true" >
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+ </FrameLayout>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="15dip"
+ android:layout_marginEnd="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v7/appcompat/res/layout/abc_simple_dropdown_hint.xml b/v7/preference/res/layout/preference_category.xml
similarity index 65%
copy from v7/appcompat/res/layout/abc_simple_dropdown_hint.xml
copy to v7/preference/res/layout/preference_category.xml
index 8326b5c..280d952 100644
--- a/v7/appcompat/res/layout/abc_simple_dropdown_hint.xml
+++ b/v7/preference/res/layout/preference_category.xml
@@ -1,23 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2006 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
-
+
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+<!-- Layout used for PreferenceCategory in a PreferenceActivity. -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:textAppearance="?android:attr/dropDownHintAppearance"
- android:singleLine="true"
- android:layout_margin="3dip"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
\ No newline at end of file
+ style="?android:attr/listSeparatorTextViewStyle"
+ android:id="@+android:id/title"
+/>
diff --git a/v7/preference/res/layout/preference_dialog_edittext.xml b/v7/preference/res/layout/preference_dialog_edittext.xml
new file mode 100644
index 0000000..527a7de
--- /dev/null
+++ b/v7/preference/res/layout/preference_dialog_edittext.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="48dp"
+ android:layout_marginBottom="48dp"
+ android:overScrollMode="ifContentScrolls">
+
+ <LinearLayout
+ android:id="@+id/edittext_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="5dip"
+ android:orientation="vertical">
+
+ <TextView android:id="@android:id/message"
+ style="?android:attr/textAppearanceSmall"
+ android:layout_marginBottom="48dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/v7/preference/res/layout/preference_information.xml b/v7/preference/res/layout/preference_information.xml
new file mode 100644
index 0000000..e3be382
--- /dev/null
+++ b/v7/preference/res/layout/preference_information.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Layout for a Preference in a PreferenceActivity. The
+ Preference is able to place a specific widget for its particular
+ type in the "widget_frame" layout. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingEnd="?android:attr/scrollbarSize">
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16sp"
+ android:layout_marginEnd="6sp"
+ android:layout_marginTop="6sp"
+ android:layout_marginBottom="6sp"
+ android:layout_weight="1">
+
+ <TextView android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <TextView android:id="@+android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="2" />
+
+ </RelativeLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
+
+</LinearLayout>
diff --git a/v7/preference/res/layout/preference_list_fragment.xml b/v7/preference/res/layout/preference_list_fragment.xml
new file mode 100644
index 0000000..44c5438
--- /dev/null
+++ b/v7/preference/res/layout/preference_list_fragment.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" >
+
+ <FrameLayout
+ android:id="@+id/list_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <TextView android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:gravity="center"
+ android:visibility="gone" />
+
+</LinearLayout>
diff --git a/v7/preference/res/layout/preference_recyclerview.xml b/v7/preference/res/layout/preference_recyclerview.xml
new file mode 100644
index 0000000..13385e6
--- /dev/null
+++ b/v7/preference/res/layout/preference_recyclerview.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list"
+ style="?attr/preferenceFragmentListStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="0dp"
+ android:paddingBottom="0dp"
+ android:clipToPadding="false" />
diff --git a/v7/preference/res/layout/preference_widget_checkbox.xml b/v7/preference/res/layout/preference_widget_checkbox.xml
new file mode 100644
index 0000000..e53b7df
--- /dev/null
+++ b/v7/preference/res/layout/preference_widget_checkbox.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<!-- Layout used by CheckBoxPreference for the checkbox style. This is inflated
+ inside android.R.layout.preference. -->
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:background="@null" />
diff --git a/v7/preference/res/layout/preference_widget_switch_compat.xml b/v7/preference/res/layout/preference_widget_switch_compat.xml
new file mode 100644
index 0000000..3324073
--- /dev/null
+++ b/v7/preference/res/layout/preference_widget_switch_compat.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<!-- Layout used by SwitchPreference for the switch widget style. This is inflated
+ inside android.R.layout.preference. -->
+<android.support.v7.widget.SwitchCompat xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/switchWidget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:background="@null" />
diff --git a/v7/preference/res/values-v17/styles.xml b/v7/preference/res/values-v17/styles.xml
new file mode 100644
index 0000000..20168b2
--- /dev/null
+++ b/v7/preference/res/values-v17/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="PreferenceFragment">
+ <item name="android:paddingStart">0dp</item>
+ <item name="android:paddingEnd">0dp</item>
+ </style>
+
+ <style name="PreferenceFragmentList">
+ <item name="android:paddingStart">16dp</item>
+ <item name="android:paddingEnd">16dp</item>
+ </style>
+
+</resources>
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
new file mode 100644
index 0000000..b93c1e6
--- /dev/null
+++ b/v7/preference/res/values/attrs.xml
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <declare-styleable name="Theme">
+
+ <!-- =================== -->
+ <!-- Preference styles -->
+ <!-- =================== -->
+ <eat-comment />
+
+ <!-- Theme for inflating Preference objects -->
+ <attr name="preferenceTheme" format="reference" />
+
+ <!-- Default style for PreferenceScreen. -->
+ <attr name="preferenceScreenStyle" format="reference" />
+ <!-- Default style for the PreferenceActivity. -->
+ <attr name="preferenceActivityStyle" format="reference" />
+ <!-- Default style for Headers pane in PreferenceActivity. -->
+ <attr name="preferenceFragmentStyle" format="reference" />
+ <!-- Default style for PreferenceCategory. -->
+ <attr name="preferenceCategoryStyle" format="reference" />
+ <!-- Default style for Preference. -->
+ <attr name="preferenceStyle" format="reference" />
+ <!-- Default style for informational Preference. -->
+ <attr name="preferenceInformationStyle" format="reference" />
+ <!-- Default style for CheckBoxPreference. -->
+ <attr name="checkBoxPreferenceStyle" format="reference" />
+ <!-- Default style for YesNoPreference. -->
+ <attr name="yesNoPreferenceStyle" format="reference" />
+ <!-- Default style for DialogPreference. -->
+ <attr name="dialogPreferenceStyle" format="reference" />
+ <!-- Default style for EditTextPreference. -->
+ <attr name="editTextPreferenceStyle" format="reference" />
+ <!-- Default style for RingtonePreference. -->
+ <attr name="ringtonePreferenceStyle" format="reference" />
+ <!-- The preference layout that has the child/tabbed effect. -->
+ <attr name="preferenceLayoutChild" format="reference" />
+ <!-- Preference panel style -->
+ <attr name="preferencePanelStyle" format="reference" />
+ <!-- Preference headers panel style -->
+ <attr name="preferenceHeaderPanelStyle" format="reference" />
+ <!-- Preference list style -->
+ <attr name="preferenceListStyle" format="reference" />
+ <!-- Preference fragment list style -->
+ <attr name="preferenceFragmentListStyle" format="reference" />
+ <!-- Preference fragment padding side -->
+ <attr name="preferenceFragmentPaddingSide" format="dimension" />
+ <!-- Default style for switch preferences. -->
+ <attr name="switchPreferenceStyle" format="reference" />
+ <!-- Default style for switch compat preferences. -->
+ <attr name="switchPreferenceCompatStyle" format="reference" />
+ <!-- Default style for seekbar preferences. -->
+ <attr name="seekBarPreferenceStyle" format="reference" />
+ </declare-styleable>
+
+ <!-- Base attributes available to PreferenceFragment. -->
+ <declare-styleable name="PreferenceFragmentCompat">
+ <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
+ <attr name="layout" />
+ <attr name="android:layout" />
+ </declare-styleable>
+
+ <!-- Base attributes available to PreferenceGroup. -->
+ <declare-styleable name="PreferenceGroup">
+ <!-- Whether to order the Preference under this group as they appear in the XML file.
+ If this is false, the ordering will follow the Preference order attribute and
+ default to alphabetic for those without the order attribute. -->
+ <attr name="orderingFromXml" format="boolean" />
+ <attr name="android:orderingFromXml" />
+ </declare-styleable>
+
+ <!-- Base attributes available to Preference. -->
+ <declare-styleable name="Preference">
+ <!-- The optional icon for the preference -->
+ <attr name="icon" />
+ <attr name="android:icon" />
+ <!-- The key to store the Preference value. -->
+ <attr name="key" format="string" />
+ <attr name="android:key" />
+ <!-- The title for the Preference in a PreferenceActivity screen. -->
+ <attr name="title" />
+ <attr name="android:title" />
+ <!-- The summary for the Preference in a PreferenceActivity screen. -->
+ <attr name="summary" format="string" />
+ <attr name="android:summary" />
+ <!-- The order for the Preference (lower values are to be ordered first). If this is not
+ specified, the default ordering will be alphabetic. -->
+ <attr name="order" format="integer" />
+ <attr name="android:order" />
+ <!-- When used inside of a modern PreferenceActivity, this declares
+ a new PreferenceFragment to be shown when the user selects this item. -->
+ <attr name="fragment" format="string" />
+ <attr name="android:fragment" />
+ <!-- The layout for the Preference in a PreferenceActivity screen. This should
+ rarely need to be changed, look at widgetLayout instead. -->
+ <attr name="layout" />
+ <attr name="android:layout" />
+ <!-- The layout for the controllable widget portion of a Preference. This is inflated
+ into the layout for a Preference and should be used more frequently than
+ the layout attribute. For example, a checkbox preference would specify
+ a custom layout (consisting of just the CheckBox) here. -->
+ <attr name="widgetLayout" format="reference" />
+ <attr name="android:widgetLayout" />
+ <!-- Whether the Preference is enabled. -->
+ <attr name="enabled" format="boolean" />
+ <attr name="android:enabled" />
+ <!-- Whether the Preference is selectable. -->
+ <attr name="selectable" format="boolean" />
+ <attr name="android:selectable" />
+ <!-- The key of another Preference that this Preference will depend on. If the other
+ Preference is not set or is off, this Preference will be disabled. -->
+ <attr name="dependency" format="string" />
+ <attr name="android:dependency" />
+ <!-- Whether the Preference stores its value to the shared preferences. -->
+ <attr name="persistent" format="boolean" />
+ <attr name="android:persistent" />
+ <!-- The default value for the preference, which will be set either if persistence
+ is off or persistence is on and the preference is not found in the persistent
+ storage. -->
+ <attr name="defaultValue" format="string|boolean|integer|reference|float" />
+ <attr name="android:defaultValue" />
+ <!-- Whether the view of this Preference should be disabled when
+ this Preference is disabled. -->
+ <attr name="shouldDisableView" format="boolean" />
+ <attr name="android:shouldDisableView" />
+ </declare-styleable>
+
+ <!-- Base attributes available to CheckBoxPreference. -->
+ <declare-styleable name="CheckBoxPreference">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ CheckBoxPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" format="string" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ CheckBoxPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" format="string" />
+ <attr name="android:summaryOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" format="boolean" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
+
+ <!-- Base attributes available to DialogPreference. -->
+ <declare-styleable name="DialogPreference">
+ <!-- The title in the dialog. -->
+ <attr name="dialogTitle" format="string" />
+ <attr name="android:dialogTitle" />
+ <!-- The message in the dialog. If a dialogLayout is provided and contains
+ a TextView with ID android:id/message, this message will be placed in there. -->
+ <attr name="dialogMessage" format="string" />
+ <attr name="android:dialogMessage" />
+ <!-- The icon for the dialog. -->
+ <attr name="dialogIcon" format="reference" />
+ <attr name="android:dialogIcon" />
+ <!-- The positive button text for the dialog. Set to @null to hide the positive button. -->
+ <attr name="positiveButtonText" format="string" />
+ <attr name="android:positiveButtonText" />
+ <!-- The negative button text for the dialog. Set to @null to hide the negative button. -->
+ <attr name="negativeButtonText" format="string" />
+ <attr name="android:negativeButtonText" />
+ <!-- A layout to be used as the content View for the dialog. By default, this shouldn't
+ be needed. If a custom DialogPreference is required, this should be set. For example,
+ the EditTextPreference uses a layout with an EditText as this attribute. -->
+ <attr name="dialogLayout" format="reference" />
+ <attr name="android:dialogLayout" />
+ </declare-styleable>
+
+ <!-- Base attributes available to ListPreference. -->
+ <declare-styleable name="ListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" format="reference" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks on the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" format="reference" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
+
+ <declare-styleable name="MultiSelectListPreference">
+ <!-- The human-readable array to present as a list. Each entry must have a corresponding
+ index in entryValues. -->
+ <attr name="entries" />
+ <attr name="android:entries" />
+ <!-- The array to find the value to save for a preference when an entry from
+ entries is selected. If a user clicks the second item in entries, the
+ second item in this array will be saved to the preference. -->
+ <attr name="entryValues" />
+ <attr name="android:entryValues" />
+ </declare-styleable>
+
+ <declare-styleable name="SwitchPreferenceCompat">
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is checked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOn" />
+ <attr name="android:summaryOn" />
+ <!-- The summary for the Preference in a PreferenceActivity screen when the
+ SwitchPreference is unchecked. If separate on/off summaries are not
+ needed, the summary attribute can be used instead. -->
+ <attr name="summaryOff" />
+ <attr name="android:summaryOff" />
+ <!-- The text used on the switch itself when in the "on" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOn" format="string" />
+ <attr name="android:switchTextOn" />
+ <!-- The text used on the switch itself when in the "off" state.
+ This should be a very SHORT string, as it appears in a small space. -->
+ <attr name="switchTextOff" format="string" />
+ <attr name="android:switchTextOff" />
+ <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
+ dependents will be disabled when this is unchecked, so the value of this preference is false. -->
+ <attr name="disableDependentsState" />
+ <attr name="android:disableDependentsState" />
+ </declare-styleable>
+
+ <declare-styleable name="PreferenceImageView">
+ <attr name="maxWidth" format="dimension" />
+ <attr name="android:maxWidth" />
+ <attr name="maxHeight" format="dimension" />
+ <attr name="android:maxHeight" />
+ </declare-styleable>
+
+</resources>
diff --git a/v7/preference/res/values/strings.xml b/v7/preference/res/values/strings.xml
new file mode 100644
index 0000000..3414e44
--- /dev/null
+++ b/v7/preference/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="v7_preference_on">ON</string>
+ <string name="v7_preference_off">OFF</string>
+</resources>
diff --git a/v7/preference/res/values/styles.xml b/v7/preference/res/values/styles.xml
new file mode 100644
index 0000000..3af31a4
--- /dev/null
+++ b/v7/preference/res/values/styles.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="Preference">
+ <item name="layout">@layout/preference</item>
+ </style>
+
+ <style name="PreferenceFragment">
+ <item name="android:paddingLeft">0dp</item>
+ <item name="android:paddingRight">0dp</item>
+ </style>
+
+ <style name="Preference.Information">
+ <item name="layout">@layout/preference_information</item>
+ <item name="enabled">false</item>
+ <item name="shouldDisableView">false</item>
+ </style>
+
+ <style name="Preference.Category">
+ <item name="layout">@layout/preference_category</item>
+ <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
+ <item name="shouldDisableView">false</item>
+ <item name="selectable">false</item>
+ </style>
+
+ <style name="Preference.CheckBoxPreference">
+ <item name="widgetLayout">@layout/preference_widget_checkbox</item>
+ </style>
+
+ <style name="Preference.SwitchPreferenceCompat">
+ <item name="widgetLayout">@layout/preference_widget_switch_compat</item>
+ <item name="switchTextOn">@string/v7_preference_on</item>
+ <item name="switchTextOff">@string/v7_preference_off</item>
+ </style>
+
+ <style name="Preference.PreferenceScreen">
+ </style>
+
+ <style name="Preference.DialogPreference">
+ <item name="positiveButtonText">@android:string/ok</item>
+ <item name="negativeButtonText">@android:string/cancel</item>
+ </style>
+
+ <style name="Preference.DialogPreference.EditTextPreference">
+ <item name="dialogLayout">@layout/preference_dialog_edittext</item>
+ </style>
+
+ <style name="PreferenceFragmentList">
+ <item name="android:paddingLeft">16dp</item>
+ <item name="android:paddingRight">16dp</item>
+ </style>
+</resources>
diff --git a/v7/preference/res/values/themes.xml b/v7/preference/res/values/themes.xml
new file mode 100644
index 0000000..c2c2c3c
--- /dev/null
+++ b/v7/preference/res/values/themes.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<resources>
+ <style name="PreferenceThemeOverlay">
+ <item name="preferenceScreenStyle">@style/Preference.PreferenceScreen</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Category</item>
+ <item name="preferenceStyle">@style/Preference</item>
+ <item name="preferenceInformationStyle">@style/Preference.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.CheckBoxPreference</item>
+ <item name="switchPreferenceCompatStyle">@style/Preference.SwitchPreferenceCompat</item>
+ <item name="dialogPreferenceStyle">@style/Preference.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList</item>
+ </style>
+</resources>
diff --git a/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java b/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java
new file mode 100644
index 0000000..e3d430d
--- /dev/null
+++ b/v7/preference/src/android/support/v7/internal/widget/PreferenceImageView.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.preference.R;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+/**
+ * Extension of ImageView that correctly applies maxWidth and maxHeight.
+ * @hide
+ */
+public class PreferenceImageView extends ImageView {
+
+ private int mMaxWidth = Integer.MAX_VALUE;
+ private int mMaxHeight = Integer.MAX_VALUE;
+
+ public PreferenceImageView(Context context) {
+ this(context, null);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.PreferenceImageView, defStyleAttr, 0);
+
+ setMaxWidth(a.getDimensionPixelSize(
+ R.styleable.PreferenceImageView_maxWidth, Integer.MAX_VALUE));
+
+ setMaxHeight(a.getDimensionPixelSize(
+ R.styleable.PreferenceImageView_maxHeight, Integer.MAX_VALUE));
+
+ a.recycle();
+ }
+
+// public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr,
+// int defStyleRes) {
+// super(context, attrs, defStyleAttr, defStyleRes);
+// }
+
+ @Override
+ public void setMaxWidth(int maxWidth) {
+ mMaxWidth = maxWidth;
+ super.setMaxWidth(maxWidth);
+ }
+
+ public int getMaxWidth() {
+ return mMaxWidth;
+ }
+
+ @Override
+ public void setMaxHeight(int maxHeight) {
+ mMaxHeight = maxHeight;
+ super.setMaxHeight(maxHeight);
+ }
+
+ public int getMaxHeight() {
+ return mMaxHeight;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int maxWidth = getMaxWidth();
+ if (maxWidth != Integer.MAX_VALUE
+ && (maxWidth < widthSize || widthMode == MeasureSpec.UNSPECIFIED)) {
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
+ }
+ }
+
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int maxHeight = getMaxHeight();
+ if (maxHeight != Integer.MAX_VALUE
+ && (maxHeight < heightSize || heightMode == MeasureSpec.UNSPECIFIED)) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
+ }
+ }
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java b/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java
new file mode 100644
index 0000000..f49b0d6
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/CheckBoxPreference.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Checkable;
+
+/**
+ * A {@link Preference} that provides checkbox widget
+ * functionality.
+ * <p>
+ * This preference will store a boolean into the SharedPreferences.
+ *
+ * @attr ref android.R.styleable#CheckBoxPreference_summaryOff
+ * @attr ref android.R.styleable#CheckBoxPreference_summaryOn
+ * @attr ref android.R.styleable#CheckBoxPreference_disableDependentsState
+ */
+public class CheckBoxPreference extends TwoStatePreference {
+
+ public CheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public CheckBoxPreference(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.CheckBoxPreference, defStyleAttr, defStyleRes);
+
+ setSummaryOn(TypedArrayUtils.getString(a, R.styleable.CheckBoxPreference_summaryOn,
+ R.styleable.CheckBoxPreference_android_summaryOn));
+
+ setSummaryOff(TypedArrayUtils.getString(a, R.styleable.CheckBoxPreference_summaryOff,
+ R.styleable.CheckBoxPreference_android_summaryOff));
+
+ setDisableDependentsState(TypedArrayUtils.getBoolean(a,
+ R.styleable.CheckBoxPreference_disableDependentsState,
+ R.styleable.CheckBoxPreference_android_disableDependentsState, false));
+
+ a.recycle();
+ }
+
+ public CheckBoxPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.checkBoxPreferenceStyle);
+ }
+
+ public CheckBoxPreference(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View checkboxView = holder.findViewById(R.id.checkbox);
+ if (checkboxView != null && checkboxView instanceof Checkable) {
+ ((Checkable) checkboxView).setChecked(mChecked);
+ }
+
+ syncSummaryView(holder);
+ }
+}
diff --git a/v7/preference/src/android/support/v7/preference/DialogPreference.java b/v7/preference/src/android/support/v7/preference/DialogPreference.java
new file mode 100644
index 0000000..bf0f4ef
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/DialogPreference.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * A base class for {@link Preference} objects that are
+ * dialog-based. These preferences will, when clicked, open a dialog showing the
+ * actual preference controls.
+ *
+ * @attr ref android.R.styleable#DialogPreference_dialogTitle
+ * @attr ref android.R.styleable#DialogPreference_dialogMessage
+ * @attr ref android.R.styleable#DialogPreference_dialogIcon
+ * @attr ref android.R.styleable#DialogPreference_dialogLayout
+ * @attr ref android.R.styleable#DialogPreference_positiveButtonText
+ * @attr ref android.R.styleable#DialogPreference_negativeButtonText
+ */
+public abstract class DialogPreference extends Preference {
+
+ public interface TargetFragment {
+ Preference findPreference(CharSequence key);
+ }
+
+ private CharSequence mDialogTitle;
+ private CharSequence mDialogMessage;
+ private Drawable mDialogIcon;
+ private CharSequence mPositiveButtonText;
+ private CharSequence mNegativeButtonText;
+ private int mDialogLayoutResId;
+
+ public DialogPreference(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.DialogPreference, defStyleAttr, defStyleRes);
+
+ mDialogTitle = TypedArrayUtils.getString(a, R.styleable.DialogPreference_dialogTitle,
+ R.styleable.DialogPreference_android_dialogTitle);
+ if (mDialogTitle == null) {
+ // Fall back on the regular title of the preference
+ // (the one that is seen in the list)
+ mDialogTitle = getTitle();
+ }
+
+ mDialogMessage = TypedArrayUtils.getString(a, R.styleable.DialogPreference_dialogMessage,
+ R.styleable.DialogPreference_android_dialogMessage);
+
+ mDialogIcon = TypedArrayUtils.getDrawable(a, R.styleable.DialogPreference_dialogIcon,
+ R.styleable.DialogPreference_android_dialogIcon);
+
+ mPositiveButtonText = TypedArrayUtils.getString(a,
+ R.styleable.DialogPreference_positiveButtonText,
+ R.styleable.DialogPreference_android_positiveButtonText);
+
+ mNegativeButtonText = TypedArrayUtils.getString(a,
+ R.styleable.DialogPreference_negativeButtonText,
+ R.styleable.DialogPreference_android_negativeButtonText);
+
+ mDialogLayoutResId = TypedArrayUtils.getResourceId(a,
+ R.styleable.DialogPreference_dialogLayout,
+ R.styleable.DialogPreference_android_dialogLayout, 0);
+
+ a.recycle();
+ }
+
+ public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DialogPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.dialogPreferenceStyle);
+ }
+
+ public DialogPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Sets the title of the dialog. This will be shown on subsequent dialogs.
+ *
+ * @param dialogTitle The title.
+ */
+ public void setDialogTitle(CharSequence dialogTitle) {
+ mDialogTitle = dialogTitle;
+ }
+
+ /**
+ * @see #setDialogTitle(CharSequence)
+ * @param dialogTitleResId The dialog title as a resource.
+ */
+ public void setDialogTitle(int dialogTitleResId) {
+ setDialogTitle(getContext().getString(dialogTitleResId));
+ }
+
+ /**
+ * Returns the title to be shown on subsequent dialogs.
+ * @return The title.
+ */
+ public CharSequence getDialogTitle() {
+ return mDialogTitle;
+ }
+
+ /**
+ * Sets the message of the dialog. This will be shown on subsequent dialogs.
+ * <p>
+ * This message forms the content View of the dialog and conflicts with
+ * list-based dialogs, for example. If setting a custom View on a dialog via
+ * {@link #setDialogLayoutResource(int)}, include a text View with ID
+ * {@link android.R.id#message} and it will be populated with this message.
+ *
+ * @param dialogMessage The message.
+ */
+ public void setDialogMessage(CharSequence dialogMessage) {
+ mDialogMessage = dialogMessage;
+ }
+
+ /**
+ * @see #setDialogMessage(CharSequence)
+ * @param dialogMessageResId The dialog message as a resource.
+ */
+ public void setDialogMessage(int dialogMessageResId) {
+ setDialogMessage(getContext().getString(dialogMessageResId));
+ }
+
+ /**
+ * Returns the message to be shown on subsequent dialogs.
+ * @return The message.
+ */
+ public CharSequence getDialogMessage() {
+ return mDialogMessage;
+ }
+
+ /**
+ * Sets the icon of the dialog. This will be shown on subsequent dialogs.
+ *
+ * @param dialogIcon The icon, as a {@link Drawable}.
+ */
+ public void setDialogIcon(Drawable dialogIcon) {
+ mDialogIcon = dialogIcon;
+ }
+
+ /**
+ * Sets the icon (resource ID) of the dialog. This will be shown on
+ * subsequent dialogs.
+ *
+ * @param dialogIconRes The icon, as a resource ID.
+ */
+ public void setDialogIcon(int dialogIconRes) {
+ mDialogIcon = ContextCompat.getDrawable(getContext(), dialogIconRes);
+ }
+
+ /**
+ * Returns the icon to be shown on subsequent dialogs.
+ * @return The icon, as a {@link Drawable}.
+ */
+ public Drawable getDialogIcon() {
+ return mDialogIcon;
+ }
+
+ /**
+ * Sets the text of the positive button of the dialog. This will be shown on
+ * subsequent dialogs.
+ *
+ * @param positiveButtonText The text of the positive button.
+ */
+ public void setPositiveButtonText(CharSequence positiveButtonText) {
+ mPositiveButtonText = positiveButtonText;
+ }
+
+ /**
+ * @see #setPositiveButtonText(CharSequence)
+ * @param positiveButtonTextResId The positive button text as a resource.
+ */
+ public void setPositiveButtonText(int positiveButtonTextResId) {
+ setPositiveButtonText(getContext().getString(positiveButtonTextResId));
+ }
+
+ /**
+ * Returns the text of the positive button to be shown on subsequent
+ * dialogs.
+ *
+ * @return The text of the positive button.
+ */
+ public CharSequence getPositiveButtonText() {
+ return mPositiveButtonText;
+ }
+
+ /**
+ * Sets the text of the negative button of the dialog. This will be shown on
+ * subsequent dialogs.
+ *
+ * @param negativeButtonText The text of the negative button.
+ */
+ public void setNegativeButtonText(CharSequence negativeButtonText) {
+ mNegativeButtonText = negativeButtonText;
+ }
+
+ /**
+ * @see #setNegativeButtonText(CharSequence)
+ * @param negativeButtonTextResId The negative button text as a resource.
+ */
+ public void setNegativeButtonText(int negativeButtonTextResId) {
+ setNegativeButtonText(getContext().getString(negativeButtonTextResId));
+ }
+
+ /**
+ * Returns the text of the negative button to be shown on subsequent
+ * dialogs.
+ *
+ * @return The text of the negative button.
+ */
+ public CharSequence getNegativeButtonText() {
+ return mNegativeButtonText;
+ }
+
+ /**
+ * Sets the layout resource that is inflated as the {@link View} to be shown
+ * as the content View of subsequent dialogs.
+ *
+ * @param dialogLayoutResId The layout resource ID to be inflated.
+ * @see #setDialogMessage(CharSequence)
+ */
+ public void setDialogLayoutResource(int dialogLayoutResId) {
+ mDialogLayoutResId = dialogLayoutResId;
+ }
+
+ /**
+ * Returns the layout resource that is used as the content View for
+ * subsequent dialogs.
+ *
+ * @return The layout resource.
+ */
+ public int getDialogLayoutResource() {
+ return mDialogLayoutResId;
+ }
+
+ @Override
+ protected void onClick() {
+ getPreferenceManager().showDialog(this);
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/EditTextPreference.java b/v7/preference/src/android/support/v7/preference/EditTextPreference.java
new file mode 100644
index 0000000..c4941e6
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/EditTextPreference.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.EditText;
+
+/**
+ * A {@link Preference} that allows for string
+ * input.
+ * <p>
+ * It is a subclass of {@link DialogPreference} and shows the {@link EditText}
+ * in a dialog.
+ * <p>
+ * This preference will store a string into the SharedPreferences.
+ */
+public class EditTextPreference extends DialogPreference {
+ private String mText;
+
+ public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public EditTextPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.editTextPreferenceStyle);
+ }
+
+ public EditTextPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Saves the text to the {@link android.content.SharedPreferences}.
+ *
+ * @param text The text to save
+ */
+ public void setText(String text) {
+ final boolean wasBlocking = shouldDisableDependents();
+
+ mText = text;
+
+ persistString(text);
+
+ final boolean isBlocking = shouldDisableDependents();
+ if (isBlocking != wasBlocking) {
+ notifyDependencyChange(isBlocking);
+ }
+ }
+
+ /**
+ * Gets the text from the {@link android.content.SharedPreferences}.
+ *
+ * @return The current preference value.
+ */
+ public String getText() {
+ return mText;
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getString(index);
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setText(restoreValue ? getPersistedString(mText) : (String) defaultValue);
+ }
+
+ @Override
+ public boolean shouldDisableDependents() {
+ return TextUtils.isEmpty(mText) || super.shouldDisableDependents();
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ myState.text = getText();
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setText(myState.text);
+ }
+
+ private static class SavedState extends BaseSavedState {
+ String text;
+
+ public SavedState(Parcel source) {
+ super(source);
+ text = source.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeString(text);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
new file mode 100644
index 0000000..182cf28
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/EditTextPreferenceDialogFragmentCompat.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.EditText;
+
+public class EditTextPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
+
+ private EditText mEditText;
+
+ public static EditTextPreferenceDialogFragmentCompat newInstance(String key) {
+ final EditTextPreferenceDialogFragmentCompat
+ fragment = new EditTextPreferenceDialogFragmentCompat();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ @Override
+ protected void onBindDialogView(View view) {
+ super.onBindDialogView(view);
+
+ mEditText = new EditText(view.getContext());
+ // Give it an ID so it can be saved/restored
+ mEditText.setId(android.R.id.edit);
+
+ mEditText.setText(getEditTextPreference().getText());
+
+ ViewParent oldParent = mEditText.getParent();
+ if (oldParent != view) {
+ if (oldParent != null) {
+ ((ViewGroup) oldParent).removeView(mEditText);
+ }
+ onAddEditTextToDialogView(view, mEditText);
+ }
+ }
+
+ private EditTextPreference getEditTextPreference() {
+ return (EditTextPreference) getPreference();
+ }
+
+ /** @hide */
+ @Override
+ protected boolean needInputMethod() {
+ // We want the input method to show, if possible, when dialog is displayed
+ return true;
+ }
+
+ /**
+ * Adds the EditText widget of this preference to the dialog's view.
+ *
+ * @param dialogView The dialog view.
+ */
+ protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
+ ViewGroup container = (ViewGroup) dialogView
+ .findViewById(R.id.edittext_container);
+ if (container != null) {
+ container.addView(editText, ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+
+ if (positiveResult) {
+ String value = mEditText.getText().toString();
+ if (getEditTextPreference().callChangeListener(value)) {
+ getEditTextPreference().setText(value);
+ }
+ }
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/ListPreference.java b/v7/preference/src/android/support/v7/preference/ListPreference.java
new file mode 100644
index 0000000..848cfad
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/ListPreference.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.ArrayRes;
+import android.support.annotation.NonNull;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+/**
+ * A {@link Preference} that displays a list of entries as
+ * a dialog.
+ * <p>
+ * This preference will store a string into the SharedPreferences. This string will be the value
+ * from the {@link #setEntryValues(CharSequence[])} array.
+ *
+ * @attr ref android.R.styleable#ListPreference_entries
+ * @attr ref android.R.styleable#ListPreference_entryValues
+ */
+public class ListPreference extends DialogPreference {
+ private CharSequence[] mEntries;
+ private CharSequence[] mEntryValues;
+ private String mValue;
+ private String mSummary;
+ private boolean mValueSet;
+
+ public ListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.ListPreference, defStyleAttr, defStyleRes);
+
+ mEntries = TypedArrayUtils.getTextArray(a, R.styleable.ListPreference_entries,
+ R.styleable.ListPreference_android_entries);
+
+ mEntryValues = TypedArrayUtils.getTextArray(a, R.styleable.ListPreference_entryValues,
+ R.styleable.ListPreference_android_entryValues);
+
+ a.recycle();
+
+ /* Retrieve the Preference summary attribute since it's private
+ * in the Preference class.
+ */
+ a = context.obtainStyledAttributes(attrs,
+ R.styleable.Preference, defStyleAttr, defStyleRes);
+
+ mSummary = TypedArrayUtils.getString(a, R.styleable.Preference_summary,
+ R.styleable.Preference_android_summary);
+
+ a.recycle();
+ }
+
+ public ListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public ListPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.dialogPreferenceStyle);
+ }
+
+ public ListPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Sets the human-readable entries to be shown in the list. This will be
+ * shown in subsequent dialogs.
+ * <p>
+ * Each entry must have a corresponding index in
+ * {@link #setEntryValues(CharSequence[])}.
+ *
+ * @param entries The entries.
+ * @see #setEntryValues(CharSequence[])
+ */
+ public void setEntries(CharSequence[] entries) {
+ mEntries = entries;
+ }
+
+ /**
+ * @see #setEntries(CharSequence[])
+ * @param entriesResId The entries array as a resource.
+ */
+ public void setEntries(@ArrayRes int entriesResId) {
+ setEntries(getContext().getResources().getTextArray(entriesResId));
+ }
+
+ /**
+ * The list of entries to be shown in the list in subsequent dialogs.
+ *
+ * @return The list as an array.
+ */
+ public CharSequence[] getEntries() {
+ return mEntries;
+ }
+
+ /**
+ * The array to find the value to save for a preference when an entry from
+ * entries is selected. If a user clicks on the second item in entries, the
+ * second item in this array will be saved to the preference.
+ *
+ * @param entryValues The array to be used as values to save for the preference.
+ */
+ public void setEntryValues(CharSequence[] entryValues) {
+ mEntryValues = entryValues;
+ }
+
+ /**
+ * @see #setEntryValues(CharSequence[])
+ * @param entryValuesResId The entry values array as a resource.
+ */
+ public void setEntryValues(@ArrayRes int entryValuesResId) {
+ setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
+ }
+
+ /**
+ * Returns the array of values to be saved for the preference.
+ *
+ * @return The array of values.
+ */
+ public CharSequence[] getEntryValues() {
+ return mEntryValues;
+ }
+
+ /**
+ * Sets the value of the key. This should be one of the entries in
+ * {@link #getEntryValues()}.
+ *
+ * @param value The value to set for the key.
+ */
+ public void setValue(String value) {
+ // Always persist/notify the first time.
+ final boolean changed = !TextUtils.equals(mValue, value);
+ if (changed || !mValueSet) {
+ mValue = value;
+ mValueSet = true;
+ persistString(value);
+ if (changed) {
+ notifyChanged();
+ }
+ }
+ }
+
+ /**
+ * Returns the summary of this ListPreference. If the summary
+ * has a {@linkplain java.lang.String#format String formatting}
+ * marker in it (i.e. "%s" or "%1$s"), then the current entry
+ * value will be substituted in its place.
+ *
+ * @return the summary with appropriate string substitution
+ */
+ @Override
+ public CharSequence getSummary() {
+ final CharSequence entry = getEntry();
+ if (mSummary == null) {
+ return super.getSummary();
+ } else {
+ return String.format(mSummary, entry == null ? "" : entry);
+ }
+ }
+
+ /**
+ * Sets the summary for this Preference with a CharSequence.
+ * If the summary has a
+ * {@linkplain java.lang.String#format String formatting}
+ * marker in it (i.e. "%s" or "%1$s"), then the current entry
+ * value will be substituted in its place when it's retrieved.
+ *
+ * @param summary The summary for the preference.
+ */
+ @Override
+ public void setSummary(CharSequence summary) {
+ super.setSummary(summary);
+ if (summary == null && mSummary != null) {
+ mSummary = null;
+ } else if (summary != null && !summary.equals(mSummary)) {
+ mSummary = summary.toString();
+ }
+ }
+
+ /**
+ * Sets the value to the given index from the entry values.
+ *
+ * @param index The index of the value to set.
+ */
+ public void setValueIndex(int index) {
+ if (mEntryValues != null) {
+ setValue(mEntryValues[index].toString());
+ }
+ }
+
+ /**
+ * Returns the value of the key. This should be one of the entries in
+ * {@link #getEntryValues()}.
+ *
+ * @return The value of the key.
+ */
+ public String getValue() {
+ return mValue;
+ }
+
+ /**
+ * Returns the entry corresponding to the current value.
+ *
+ * @return The entry corresponding to the current value, or null.
+ */
+ public CharSequence getEntry() {
+ int index = getValueIndex();
+ return index >= 0 && mEntries != null ? mEntries[index] : null;
+ }
+
+ /**
+ * Returns the index of the given value (in the entry values array).
+ *
+ * @param value The value whose index should be returned.
+ * @return The index of the value, or -1 if not found.
+ */
+ public int findIndexOfValue(String value) {
+ if (value != null && mEntryValues != null) {
+ for (int i = mEntryValues.length - 1; i >= 0; i--) {
+ if (mEntryValues[i].equals(value)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ private int getValueIndex() {
+ return findIndexOfValue(mValue);
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getString(index);
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ myState.value = getValue();
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setValue(myState.value);
+ }
+
+ private static class SavedState extends BaseSavedState {
+ String value;
+
+ public SavedState(Parcel source) {
+ super(source);
+ value = source.readString();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeString(value);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java
new file mode 100644
index 0000000..351ed0b
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/ListPreferenceDialogFragmentCompat.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+
+public class ListPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
+
+ private int mClickedDialogEntryIndex;
+
+ public static ListPreferenceDialogFragmentCompat newInstance(String key) {
+ final ListPreferenceDialogFragmentCompat fragment =
+ new ListPreferenceDialogFragmentCompat();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ private ListPreference getListPreference() {
+ return (ListPreference) getPreference();
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+
+ final ListPreference preference = getListPreference();
+
+ if (preference.getEntries() == null || preference.getEntryValues() == null) {
+ throw new IllegalStateException(
+ "ListPreference requires an entries array and an entryValues array.");
+ }
+
+ mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue());
+ builder.setSingleChoiceItems(preference.getEntries(), mClickedDialogEntryIndex,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mClickedDialogEntryIndex = which;
+
+ /*
+ * Clicking on an item simulates the positive button
+ * click, and dismisses the dialog.
+ */
+ ListPreferenceDialogFragmentCompat.this.onClick(dialog,
+ DialogInterface.BUTTON_POSITIVE);
+ dialog.dismiss();
+ }
+ });
+
+ /*
+ * The typical interaction for list-based dialogs is to have
+ * click-on-an-item dismiss the dialog instead of the user having to
+ * press 'Ok'.
+ */
+ builder.setPositiveButton(null, null);
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {
+ final ListPreference preference = getListPreference();
+ if (positiveResult && mClickedDialogEntryIndex >= 0 &&
+ preference.getEntryValues() != null) {
+ String value = preference.getEntryValues()[mClickedDialogEntryIndex].toString();
+ if (preference.callChangeListener(value)) {
+ preference.setValue(value);
+ }
+ }
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
new file mode 100644
index 0000000..7d01005
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -0,0 +1,1688 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.SharedPreferencesCompat;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.AbsSavedState;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the basic Preference UI building
+ * block displayed by a {@link PreferenceFragmentCompat} in the form of a
+ * {@link android.support.v7.widget.RecyclerView}. This class provides data for the
+ * {@link android.view.View} to be displayed
+ * in the list and associates with a {@link SharedPreferences} to
+ * store/retrieve the preference data.
+ * <p>
+ * When specifying a preference hierarchy in XML, each element can point to a
+ * subclass of {@link Preference}, similar to the view hierarchy and layouts.
+ * <p>
+ * This class contains a {@code key} that will be used as the key into the
+ * {@link SharedPreferences}. It is up to the subclass to decide how to store
+ * the value.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about building a settings UI with Preferences,
+ * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
+ * guide.</p>
+ * </div>
+ *
+ * @attr ref android.R.styleable#Preference_icon
+ * @attr ref android.R.styleable#Preference_key
+ * @attr ref android.R.styleable#Preference_title
+ * @attr ref android.R.styleable#Preference_summary
+ * @attr ref android.R.styleable#Preference_order
+ * @attr ref android.R.styleable#Preference_fragment
+ * @attr ref android.R.styleable#Preference_layout
+ * @attr ref android.R.styleable#Preference_widgetLayout
+ * @attr ref android.R.styleable#Preference_enabled
+ * @attr ref android.R.styleable#Preference_selectable
+ * @attr ref android.R.styleable#Preference_dependency
+ * @attr ref android.R.styleable#Preference_persistent
+ * @attr ref android.R.styleable#Preference_defaultValue
+ * @attr ref android.R.styleable#Preference_shouldDisableView
+ */
+public class Preference implements Comparable<Preference> {
+ /**
+ * Specify for {@link #setOrder(int)} if a specific order is not required.
+ */
+ public static final int DEFAULT_ORDER = Integer.MAX_VALUE;
+
+ private Context mContext;
+ private PreferenceManager mPreferenceManager;
+
+ /**
+ * Set when added to hierarchy since we need a unique ID within that
+ * hierarchy.
+ */
+ private long mId;
+
+ private OnPreferenceChangeListener mOnChangeListener;
+ private OnPreferenceClickListener mOnClickListener;
+
+ private int mOrder = DEFAULT_ORDER;
+ private CharSequence mTitle;
+ private CharSequence mSummary;
+ /**
+ * mIconResId is overridden by mIcon, if mIcon is specified.
+ */
+ private int mIconResId;
+ private Drawable mIcon;
+ private String mKey;
+ private Intent mIntent;
+ private String mFragment;
+ private Bundle mExtras;
+ private boolean mEnabled = true;
+ private boolean mSelectable = true;
+ private boolean mRequiresKey;
+ private boolean mPersistent = true;
+ private String mDependencyKey;
+ private Object mDefaultValue;
+ private boolean mDependencyMet = true;
+ private boolean mParentDependencyMet = true;
+ private boolean mVisible = true;
+
+ /**
+ * @see #setShouldDisableView(boolean)
+ */
+ private boolean mShouldDisableView = true;
+
+ private int mLayoutResId = R.layout.preference;
+ private int mWidgetLayoutResId;
+
+ private OnPreferenceChangeInternalListener mListener;
+
+ private List<Preference> mDependents;
+
+ private boolean mBaseMethodCalled;
+
+ private final View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ performClick();
+ }
+ };
+
+ /**
+ * Interface definition for a callback to be invoked when the value of this
+ * {@link Preference} has been changed by the user and is
+ * about to be set and/or persisted. This gives the client a chance
+ * to prevent setting and/or persisting the value.
+ */
+ public interface OnPreferenceChangeListener {
+ /**
+ * Called when a Preference has been changed by the user. This is
+ * called before the state of the Preference is about to be updated and
+ * before the state is persisted.
+ *
+ * @param preference The changed Preference.
+ * @param newValue The new value of the Preference.
+ * @return True to update the state of the Preference with the new value.
+ */
+ boolean onPreferenceChange(Preference preference, Object newValue);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a {@link Preference} is
+ * clicked.
+ */
+ public interface OnPreferenceClickListener {
+ /**
+ * Called when a Preference has been clicked.
+ *
+ * @param preference The Preference that was clicked.
+ * @return True if the click was handled.
+ */
+ boolean onPreferenceClick(Preference preference);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when this
+ * {@link Preference} is changed or, if this is a group, there is an
+ * addition/removal of {@link Preference}(s). This is used internally.
+ */
+ interface OnPreferenceChangeInternalListener {
+ /**
+ * Called when this Preference has changed.
+ *
+ * @param preference This preference.
+ */
+ void onPreferenceChange(Preference preference);
+
+ /**
+ * Called when this group has added/removed {@link Preference}(s).
+ *
+ * @param preference This Preference.
+ */
+ void onPreferenceHierarchyChange(Preference preference);
+
+ /**
+ * Called when this preference has changed its visibility.
+ *
+ * @param preference This Preference.
+ */
+ void onPreferenceVisibilityChange(Preference preference);
+ }
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style. This
+ * constructor of Preference allows subclasses to use their own base style
+ * when they are inflating. For example, a {@link CheckBoxPreference}
+ * constructor calls this version of the super class constructor and
+ * supplies {@code android.R.attr.checkBoxPreferenceStyle} for
+ * <var>defStyleAttr</var>. This allows the theme's checkbox preference
+ * style to modify all of the base preference attributes as well as the
+ * {@link CheckBoxPreference} class's attributes.
+ *
+ * @param context The Context this is associated with, through which it can
+ * access the current theme, resources,
+ * {@link android.content.SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the
+ * preference.
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ * @param defStyleRes A resource identifier of a style resource that
+ * supplies default values for the view, used only if
+ * defStyleAttr is 0 or can not be found in the theme. Can be 0
+ * to not look for defaults.
+ * @see #Preference(Context, android.util.AttributeSet)
+ */
+ public Preference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ mContext = context;
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.Preference, defStyleAttr, defStyleRes);
+
+ mIconResId = TypedArrayUtils.getResourceId(a, R.styleable.Preference_icon,
+ R.styleable.Preference_android_icon, 0);
+
+ mKey = TypedArrayUtils.getString(a, R.styleable.Preference_key,
+ R.styleable.Preference_android_key);
+
+ mTitle = TypedArrayUtils.getString(a, R.styleable.Preference_title,
+ R.styleable.Preference_android_title);
+
+ mSummary = TypedArrayUtils.getString(a, R.styleable.Preference_summary,
+ R.styleable.Preference_android_summary);
+
+ mOrder = TypedArrayUtils.getInt(a, R.styleable.Preference_order,
+ R.styleable.Preference_android_order, DEFAULT_ORDER);
+
+ mFragment = TypedArrayUtils.getString(a, R.styleable.Preference_fragment,
+ R.styleable.Preference_android_fragment);
+
+ mLayoutResId = TypedArrayUtils.getResourceId(a, R.styleable.Preference_layout,
+ R.styleable.Preference_android_layout, R.layout.preference);
+
+ mWidgetLayoutResId = TypedArrayUtils.getResourceId(a, R.styleable.Preference_widgetLayout,
+ R.styleable.Preference_android_widgetLayout, 0);
+
+ mEnabled = TypedArrayUtils.getBoolean(a, R.styleable.Preference_enabled,
+ R.styleable.Preference_android_enabled, true);
+
+ mSelectable = TypedArrayUtils.getBoolean(a, R.styleable.Preference_selectable,
+ R.styleable.Preference_android_selectable, true);
+
+ mPersistent = TypedArrayUtils.getBoolean(a, R.styleable.Preference_persistent,
+ R.styleable.Preference_android_persistent, true);
+
+ mDependencyKey = TypedArrayUtils.getString(a, R.styleable.Preference_dependency,
+ R.styleable.Preference_android_dependency);
+
+ if (a.hasValue(R.styleable.Preference_defaultValue)) {
+ mDefaultValue = onGetDefaultValue(a, R.styleable.Preference_defaultValue);
+ } else if (a.hasValue(R.styleable.Preference_android_defaultValue)) {
+ mDefaultValue = onGetDefaultValue(a, R.styleable.Preference_android_defaultValue);
+ }
+
+ mShouldDisableView =
+ TypedArrayUtils.getBoolean(a, R.styleable.Preference_shouldDisableView,
+ R.styleable.Preference_shouldDisableView, true);
+
+ a.recycle();
+ }
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style. This
+ * constructor of Preference allows subclasses to use their own base style
+ * when they are inflating. For example, a {@link CheckBoxPreference}
+ * constructor calls this version of the super class constructor and
+ * supplies {@code android.R.attr.checkBoxPreferenceStyle} for
+ * <var>defStyleAttr</var>. This allows the theme's checkbox preference
+ * style to modify all of the base preference attributes as well as the
+ * {@link CheckBoxPreference} class's attributes.
+ *
+ * @param context The Context this is associated with, through which it can
+ * access the current theme, resources,
+ * {@link android.content.SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the
+ * preference.
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ * @see #Preference(Context, AttributeSet)
+ */
+ public Preference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ /**
+ * Constructor that is called when inflating a Preference from XML. This is
+ * called when a Preference is being constructed from an XML file, supplying
+ * attributes that were specified in the XML file. This version uses a
+ * default style of 0, so the only attribute values applied are those in the
+ * Context's Theme and the given AttributeSet.
+ *
+ * @param context The Context this is associated with, through which it can
+ * access the current theme, resources, {@link android.content.SharedPreferences},
+ * etc.
+ * @param attrs The attributes of the XML tag that is inflating the
+ * preference.
+ * @see #Preference(Context, AttributeSet, int)
+ */
+ public Preference(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.preferenceStyle);
+ }
+
+ /**
+ * Constructor to create a Preference.
+ *
+ * @param context The Context in which to store Preference values.
+ */
+ public Preference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Called when a Preference is being inflated and the default value
+ * attribute needs to be read. Since different Preference types have
+ * different value types, the subclass should get and return the default
+ * value which will be its value type.
+ * <p>
+ * For example, if the value type is String, the body of the method would
+ * proxy to {@link TypedArray#getString(int)}.
+ *
+ * @param a The set of attributes.
+ * @param index The index of the default value attribute.
+ * @return The default value of this preference type.
+ */
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return null;
+ }
+
+ /**
+ * Sets an {@link Intent} to be used for
+ * {@link Context#startActivity(Intent)} when this Preference is clicked.
+ *
+ * @param intent The intent associated with this Preference.
+ */
+ public void setIntent(Intent intent) {
+ mIntent = intent;
+ }
+
+ /**
+ * Return the {@link Intent} associated with this Preference.
+ *
+ * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML.
+ */
+ public Intent getIntent() {
+ return mIntent;
+ }
+
+ /**
+ * Sets the class name of a fragment to be shown when this Preference is clicked.
+ *
+ * @param fragment The class name of the fragment associated with this Preference.
+ */
+ public void setFragment(String fragment) {
+ mFragment = fragment;
+ }
+
+ /**
+ * Return the fragment class name associated with this Preference.
+ *
+ * @return The fragment class name last set via {@link #setFragment} or XML.
+ */
+ public String getFragment() {
+ return mFragment;
+ }
+
+ /**
+ * Return the extras Bundle object associated with this preference, creating
+ * a new Bundle if there currently isn't one. You can use this to get and
+ * set individual extra key/value pairs.
+ */
+ public Bundle getExtras() {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ return mExtras;
+ }
+
+ /**
+ * Return the extras Bundle object associated with this preference,
+ * returning null if there is not currently one.
+ */
+ public Bundle peekExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Sets the layout resource that is inflated as the {@link View} to be shown
+ * for this Preference. In most cases, the default layout is sufficient for
+ * custom Preference objects and only the widget layout needs to be changed.
+ * <p>
+ * This layout should contain a {@link ViewGroup} with ID
+ * {@link android.R.id#widget_frame} to be the parent of the specific widget
+ * for this Preference. It should similarly contain
+ * {@link android.R.id#title} and {@link android.R.id#summary}.
+ * <p>
+ * It is an error to change the layout after adding the preference to a {@link PreferenceGroup}
+ *
+ * @param layoutResId The layout resource ID to be inflated and returned as
+ * a {@link View}.
+ * @see #setWidgetLayoutResource(int)
+ */
+ public void setLayoutResource(int layoutResId) {
+ mLayoutResId = layoutResId;
+ }
+
+ /**
+ * Gets the layout resource that will be shown as the {@link View} for this Preference.
+ *
+ * @return The layout resource ID.
+ */
+ public final int getLayoutResource() {
+ return mLayoutResId;
+ }
+
+ /**
+ * Sets the layout for the controllable widget portion of this Preference. This
+ * is inflated into the main layout. For example, a {@link CheckBoxPreference}
+ * would specify a custom layout (consisting of just the CheckBox) here,
+ * instead of creating its own main layout.
+ * <p>
+ * It is an error to change the layout after adding the preference to a {@link PreferenceGroup}
+ *
+ * @param widgetLayoutResId The layout resource ID to be inflated into the
+ * main layout.
+ * @see #setLayoutResource(int)
+ */
+ public void setWidgetLayoutResource(int widgetLayoutResId) {
+ mWidgetLayoutResId = widgetLayoutResId;
+ }
+
+ /**
+ * Gets the layout resource for the controllable widget portion of this Preference.
+ *
+ * @return The layout resource ID.
+ */
+ public final int getWidgetLayoutResource() {
+ return mWidgetLayoutResId;
+ }
+
+ /**
+ * Binds the created View to the data for this Preference.
+ * <p>
+ * This is a good place to grab references to custom Views in the layout and
+ * set properties on them.
+ * <p>
+ * Make sure to call through to the superclass's implementation.
+ *
+ * @param holder The ViewHolder that provides references to the views to fill in. These views
+ * will be recycled, so you should not hold a reference to them after this method
+ * returns.
+ */
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ holder.itemView.setOnClickListener(mClickListener);
+
+ final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
+ if (titleView != null) {
+ final CharSequence title = getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ titleView.setText(title);
+ titleView.setVisibility(View.VISIBLE);
+ } else {
+ titleView.setVisibility(View.GONE);
+ }
+ }
+
+ final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+ if (summaryView != null) {
+ final CharSequence summary = getSummary();
+ if (!TextUtils.isEmpty(summary)) {
+ summaryView.setText(summary);
+ summaryView.setVisibility(View.VISIBLE);
+ } else {
+ summaryView.setVisibility(View.GONE);
+ }
+ }
+
+ final ImageView imageView = (ImageView) holder.findViewById(android.R.id.icon);
+ if (imageView != null) {
+ if (mIconResId != 0 || mIcon != null) {
+ if (mIcon == null) {
+ mIcon = ContextCompat.getDrawable(getContext(), mIconResId);
+ }
+ if (mIcon != null) {
+ imageView.setImageDrawable(mIcon);
+ }
+ }
+ imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
+ }
+
+ final View imageFrame = holder.findViewById(R.id.icon_frame);
+ if (imageFrame != null) {
+ imageFrame.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
+ }
+
+ if (mShouldDisableView) {
+ setEnabledStateOnViews(holder.itemView, isEnabled());
+ } else {
+ setEnabledStateOnViews(holder.itemView, true);
+ }
+ }
+
+ /**
+ * Makes sure the view (and any children) get the enabled state changed.
+ */
+ private void setEnabledStateOnViews(View v, boolean enabled) {
+ v.setEnabled(enabled);
+
+ if (v instanceof ViewGroup) {
+ final ViewGroup vg = (ViewGroup) v;
+ for (int i = vg.getChildCount() - 1; i >= 0; i--) {
+ setEnabledStateOnViews(vg.getChildAt(i), enabled);
+ }
+ }
+ }
+
+ /**
+ * Sets the order of this Preference with respect to other
+ * Preference objects on the same level. If this is not specified, the
+ * default behavior is to sort alphabetically. The
+ * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order
+ * Preference objects based on the order they appear in the XML.
+ *
+ * @param order The order for this Preference. A lower value will be shown
+ * first. Use {@link #DEFAULT_ORDER} to sort alphabetically or
+ * allow ordering from XML.
+ * @see PreferenceGroup#setOrderingAsAdded(boolean)
+ * @see #DEFAULT_ORDER
+ */
+ public void setOrder(int order) {
+ if (order != mOrder) {
+ mOrder = order;
+
+ // Reorder the list
+ notifyHierarchyChanged();
+ }
+ }
+
+ /**
+ * Gets the order of this Preference with respect to other Preference objects
+ * on the same level.
+ *
+ * @return The order of this Preference.
+ * @see #setOrder(int)
+ */
+ public int getOrder() {
+ return mOrder;
+ }
+
+ /**
+ * Sets the title for this Preference with a CharSequence.
+ * This title will be placed into the ID
+ * {@link android.R.id#title} within the View bound by
+ * {@link #onBindViewHolder(PreferenceViewHolder)}.
+ *
+ * @param title The title for this Preference.
+ */
+ public void setTitle(CharSequence title) {
+ if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {
+ mTitle = title;
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Sets the title for this Preference with a resource ID.
+ *
+ * @see #setTitle(CharSequence)
+ * @param titleResId The title as a resource ID.
+ */
+ public void setTitle(int titleResId) {
+ setTitle(mContext.getString(titleResId));
+ }
+
+ /**
+ * Returns the title of this Preference.
+ *
+ * @return The title.
+ * @see #setTitle(CharSequence)
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Sets the icon for this Preference with a Drawable.
+ * This icon will be placed into the ID
+ * {@link android.R.id#icon} within the View created by
+ * {@link #onBindViewHolder(PreferenceViewHolder)}.
+ *
+ * @param icon The optional icon for this Preference.
+ */
+ public void setIcon(Drawable icon) {
+ if ((icon == null && mIcon != null) || (icon != null && mIcon != icon)) {
+ mIcon = icon;
+ mIconResId = 0;
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Sets the icon for this Preference with a resource ID.
+ *
+ * @see #setIcon(Drawable)
+ * @param iconResId The icon as a resource ID.
+ */
+ public void setIcon(int iconResId) {
+ setIcon(ContextCompat.getDrawable(mContext, iconResId));
+ mIconResId = iconResId;
+ }
+
+ /**
+ * Returns the icon of this Preference.
+ *
+ * @return The icon.
+ * @see #setIcon(Drawable)
+ */
+ public Drawable getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * Returns the summary of this Preference.
+ *
+ * @return The summary.
+ * @see #setSummary(CharSequence)
+ */
+ public CharSequence getSummary() {
+ return mSummary;
+ }
+
+ /**
+ * Sets the summary for this Preference with a CharSequence.
+ *
+ * @param summary The summary for the preference.
+ */
+ public void setSummary(CharSequence summary) {
+ if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) {
+ mSummary = summary;
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Sets the summary for this Preference with a resource ID.
+ *
+ * @see #setSummary(CharSequence)
+ * @param summaryResId The summary as a resource.
+ */
+ public void setSummary(int summaryResId) {
+ setSummary(mContext.getString(summaryResId));
+ }
+
+ /**
+ * Sets whether this Preference is enabled. If disabled, it will
+ * not handle clicks.
+ *
+ * @param enabled Set true to enable it.
+ */
+ public void setEnabled(boolean enabled) {
+ if (mEnabled != enabled) {
+ mEnabled = enabled;
+
+ // Enabled state can change dependent preferences' states, so notify
+ notifyDependencyChange(shouldDisableDependents());
+
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Checks whether this Preference should be enabled in the list.
+ *
+ * @return True if this Preference is enabled, false otherwise.
+ */
+ public boolean isEnabled() {
+ return mEnabled && mDependencyMet && mParentDependencyMet;
+ }
+
+ /**
+ * Sets whether this Preference is selectable.
+ *
+ * @param selectable Set true to make it selectable.
+ */
+ public void setSelectable(boolean selectable) {
+ if (mSelectable != selectable) {
+ mSelectable = selectable;
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Checks whether this Preference should be selectable in the list.
+ *
+ * @return True if it is selectable, false otherwise.
+ */
+ public boolean isSelectable() {
+ return mSelectable;
+ }
+
+ /**
+ * Sets whether this Preference should disable its view when it gets
+ * disabled.
+ * <p>
+ * For example, set this and {@link #setEnabled(boolean)} to false for
+ * preferences that are only displaying information and 1) should not be
+ * clickable 2) should not have the view set to the disabled state.
+ *
+ * @param shouldDisableView Set true if this preference should disable its view
+ * when the preference is disabled.
+ */
+ public void setShouldDisableView(boolean shouldDisableView) {
+ mShouldDisableView = shouldDisableView;
+ notifyChanged();
+ }
+
+ /**
+ * Checks whether this Preference should disable its view when it's action is disabled.
+ * @see #setShouldDisableView(boolean)
+ * @return True if it should disable the view.
+ */
+ public boolean getShouldDisableView() {
+ return mShouldDisableView;
+ }
+
+ /**
+ * Sets whether this preference should be visible in the list. If false, it is excluded from
+ * the adapter, but can still be retrieved using
+ * {@link PreferenceFragmentCompat#findPreference(CharSequence)}.
+ *
+ * @param visible Set false if this preference should be hidden from the list.
+ */
+ public final void setVisible(boolean visible) {
+ mVisible = visible;
+ if (mListener != null) {
+ mListener.onPreferenceVisibilityChange(this);
+ }
+ }
+
+ /**
+ * Checks whether this preference should be visible to the user in the list.
+ * @see #setVisible(boolean)
+ * @return True if this preference should be displayed.
+ */
+ public final boolean isVisible() {
+ return mVisible;
+ }
+
+ /**
+ * Returns a unique ID for this Preference. This ID should be unique across all
+ * Preference objects in a hierarchy.
+ *
+ * @return A unique ID for this Preference.
+ */
+ long getId() {
+ return mId;
+ }
+
+ /**
+ * Processes a click on the preference. This includes saving the value to
+ * the {@link android.content.SharedPreferences}. However, the overridden method should
+ * call {@link #callChangeListener(Object)} to make sure the client wants to
+ * update the preference's state with the new value.
+ */
+ protected void onClick() {
+ }
+
+ /**
+ * Sets the key for this Preference, which is used as a key to the
+ * {@link android.content.SharedPreferences}. This should be unique for the package.
+ *
+ * @param key The key for the preference.
+ */
+ public void setKey(String key) {
+ mKey = key;
+
+ if (mRequiresKey && !hasKey()) {
+ requireKey();
+ }
+ }
+
+ /**
+ * Gets the key for this Preference, which is also the key used for storing
+ * values into SharedPreferences.
+ *
+ * @return The key.
+ */
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * Checks whether the key is present, and if it isn't throws an
+ * exception. This should be called by subclasses that store preferences in
+ * the {@link android.content.SharedPreferences}.
+ *
+ * @throws IllegalStateException If there is no key assigned.
+ */
+ void requireKey() {
+ if (TextUtils.isEmpty(mKey)) {
+ throw new IllegalStateException("Preference does not have a key assigned.");
+ }
+
+ mRequiresKey = true;
+ }
+
+ /**
+ * Checks whether this Preference has a valid key.
+ *
+ * @return True if the key exists and is not a blank string, false otherwise.
+ */
+ public boolean hasKey() {
+ return !TextUtils.isEmpty(mKey);
+ }
+
+ /**
+ * Checks whether this Preference is persistent. If it is, it stores its value(s) into
+ * the persistent {@link android.content.SharedPreferences} storage.
+ *
+ * @return True if it is persistent.
+ */
+ public boolean isPersistent() {
+ return mPersistent;
+ }
+
+ /**
+ * Checks whether, at the given time this method is called,
+ * this Preference should store/restore its value(s) into the
+ * {@link android.content.SharedPreferences}. This, at minimum, checks whether this
+ * Preference is persistent and it currently has a key. Before you
+ * save/restore from the {@link android.content.SharedPreferences}, check this first.
+ *
+ * @return True if it should persist the value.
+ */
+ protected boolean shouldPersist() {
+ return mPreferenceManager != null && isPersistent() && hasKey();
+ }
+
+ /**
+ * Sets whether this Preference is persistent. When persistent,
+ * it stores its value(s) into the persistent {@link android.content.SharedPreferences}
+ * storage.
+ *
+ * @param persistent Set true if it should store its value(s) into the
+ * {@link android.content.SharedPreferences}.
+ */
+ public void setPersistent(boolean persistent) {
+ mPersistent = persistent;
+ }
+
+ /**
+ * Call this method after the user changes the preference, but before the
+ * internal state is set. This allows the client to ignore the user value.
+ *
+ * @param newValue The new value of this Preference.
+ * @return True if the user value should be set as the preference
+ * value (and persisted).
+ */
+ public boolean callChangeListener(Object newValue) {
+ return mOnChangeListener == null || mOnChangeListener.onPreferenceChange(this, newValue);
+ }
+
+ /**
+ * Sets the callback to be invoked when this Preference is changed by the
+ * user (but before the internal state has been updated).
+ *
+ * @param onPreferenceChangeListener The callback to be invoked.
+ */
+ public void setOnPreferenceChangeListener(
+ OnPreferenceChangeListener onPreferenceChangeListener) {
+ mOnChangeListener = onPreferenceChangeListener;
+ }
+
+ /**
+ * Returns the callback to be invoked when this Preference is changed by the
+ * user (but before the internal state has been updated).
+ *
+ * @return The callback to be invoked.
+ */
+ public OnPreferenceChangeListener getOnPreferenceChangeListener() {
+ return mOnChangeListener;
+ }
+
+ /**
+ * Sets the callback to be invoked when this Preference is clicked.
+ *
+ * @param onPreferenceClickListener The callback to be invoked.
+ */
+ public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
+ mOnClickListener = onPreferenceClickListener;
+ }
+
+ /**
+ * Returns the callback to be invoked when this Preference is clicked.
+ *
+ * @return The callback to be invoked.
+ */
+ public OnPreferenceClickListener getOnPreferenceClickListener() {
+ return mOnClickListener;
+ }
+
+ /**
+ * Called when a click should be performed.
+ *
+ * @hide
+ */
+ public void performClick() {
+
+ if (!isEnabled()) {
+ return;
+ }
+
+ onClick();
+
+ if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
+ return;
+ }
+
+ PreferenceManager preferenceManager = getPreferenceManager();
+ if (preferenceManager != null) {
+ PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
+ .getOnPreferenceTreeClickListener();
+ if (listener != null && listener.onPreferenceTreeClick(this)) {
+ return;
+ }
+ }
+
+ if (mIntent != null) {
+ Context context = getContext();
+ context.startActivity(mIntent);
+ }
+ }
+
+ /**
+ * Returns the {@link android.content.Context} of this Preference.
+ * Each Preference in a Preference hierarchy can be
+ * from different Context (for example, if multiple activities provide preferences into a single
+ * {@link PreferenceFragmentCompat}). This Context will be used to save the Preference values.
+ *
+ * @return The Context of this Preference.
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns the {@link android.content.SharedPreferences} where this Preference can read its
+ * value(s). Usually, it's easier to use one of the helper read methods:
+ * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)},
+ * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)},
+ * {@link #getPersistedString(String)}. To save values, see
+ * {@link #getEditor()}.
+ * <p>
+ * In some cases, writes to the {@link #getEditor()} will not be committed
+ * right away and hence not show up in the returned
+ * {@link android.content.SharedPreferences}, this is intended behavior to improve
+ * performance.
+ *
+ * @return The {@link android.content.SharedPreferences} where this Preference reads its
+ * value(s), or null if it isn't attached to a Preference hierarchy.
+ * @see #getEditor()
+ */
+ public SharedPreferences getSharedPreferences() {
+ if (mPreferenceManager == null) {
+ return null;
+ }
+
+ return mPreferenceManager.getSharedPreferences();
+ }
+
+ /**
+ * Compares Preference objects based on order (if set), otherwise alphabetically on the titles.
+ *
+ * @param another The Preference to compare to this one.
+ * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
+ * greater than 0 if this Preference sorts after <var>another</var>.
+ */
+ @Override
+ public int compareTo(@NonNull Preference another) {
+ if (mOrder != another.mOrder) {
+ // Do order comparison
+ return mOrder - another.mOrder;
+ } else if (mTitle == another.mTitle) {
+ // If titles are null or share same object comparison
+ return 0;
+ } else if (mTitle == null) {
+ return 1;
+ } else if (another.mTitle == null) {
+ return -1;
+ } else {
+ // Do name comparison
+ return mTitle.toString().compareToIgnoreCase(another.mTitle.toString());
+ }
+ }
+
+ /**
+ * Sets the internal change listener.
+ *
+ * @param listener The listener.
+ * @see #notifyChanged()
+ */
+ final void setOnPreferenceChangeInternalListener(OnPreferenceChangeInternalListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Should be called when the data of this {@link Preference} has changed.
+ */
+ protected void notifyChanged() {
+ if (mListener != null) {
+ mListener.onPreferenceChange(this);
+ }
+ }
+
+ /**
+ * Should be called when a Preference has been
+ * added/removed from this group, or the ordering should be
+ * re-evaluated.
+ */
+ protected void notifyHierarchyChanged() {
+ if (mListener != null) {
+ mListener.onPreferenceHierarchyChange(this);
+ }
+ }
+
+ /**
+ * Gets the {@link PreferenceManager} that manages this Preference object's tree.
+ *
+ * @return The {@link PreferenceManager}.
+ */
+ public PreferenceManager getPreferenceManager() {
+ return mPreferenceManager;
+ }
+
+ /**
+ * Called when this Preference has been attached to a Preference hierarchy.
+ * Make sure to call the super implementation.
+ *
+ * @param preferenceManager The PreferenceManager of the hierarchy.
+ */
+ protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
+ mPreferenceManager = preferenceManager;
+
+ mId = preferenceManager.getNextId();
+
+ dispatchSetInitialValue();
+ }
+
+ /**
+ * Called when the Preference hierarchy has been attached to the
+ * list of preferences. This can also be called when this
+ * Preference has been attached to a group that was already attached
+ * to the list of preferences.
+ */
+ protected void onAttached() {
+ // At this point, the hierarchy that this preference is in is connected
+ // with all other preferences.
+ registerDependency();
+ }
+
+ private void registerDependency() {
+
+ if (TextUtils.isEmpty(mDependencyKey)) return;
+
+ Preference preference = findPreferenceInHierarchy(mDependencyKey);
+ if (preference != null) {
+ preference.registerDependent(this);
+ } else {
+ throw new IllegalStateException("Dependency \"" + mDependencyKey
+ + "\" not found for preference \"" + mKey + "\" (title: \"" + mTitle + "\"");
+ }
+ }
+
+ private void unregisterDependency() {
+ if (mDependencyKey != null) {
+ final Preference oldDependency = findPreferenceInHierarchy(mDependencyKey);
+ if (oldDependency != null) {
+ oldDependency.unregisterDependent(this);
+ }
+ }
+ }
+
+ /**
+ * Finds a Preference in this hierarchy (the whole thing,
+ * even above/below your {@link PreferenceScreen} screen break) with the given
+ * key.
+ * <p>
+ * This only functions after we have been attached to a hierarchy.
+ *
+ * @param key The key of the Preference to find.
+ * @return The Preference that uses the given key.
+ */
+ protected Preference findPreferenceInHierarchy(String key) {
+ if (TextUtils.isEmpty(key) || mPreferenceManager == null) {
+ return null;
+ }
+
+ return mPreferenceManager.findPreference(key);
+ }
+
+ /**
+ * Adds a dependent Preference on this Preference so we can notify it.
+ * Usually, the dependent Preference registers itself (it's good for it to
+ * know it depends on something), so please use
+ * {@link Preference#setDependency(String)} on the dependent Preference.
+ *
+ * @param dependent The dependent Preference that will be enabled/disabled
+ * according to the state of this Preference.
+ */
+ private void registerDependent(Preference dependent) {
+ if (mDependents == null) {
+ mDependents = new ArrayList<Preference>();
+ }
+
+ mDependents.add(dependent);
+
+ dependent.onDependencyChanged(this, shouldDisableDependents());
+ }
+
+ /**
+ * Removes a dependent Preference on this Preference.
+ *
+ * @param dependent The dependent Preference that will be enabled/disabled
+ * according to the state of this Preference.
+ * @return Returns the same Preference object, for chaining multiple calls
+ * into a single statement.
+ */
+ private void unregisterDependent(Preference dependent) {
+ if (mDependents != null) {
+ mDependents.remove(dependent);
+ }
+ }
+
+ /**
+ * Notifies any listening dependents of a change that affects the
+ * dependency.
+ *
+ * @param disableDependents Whether this Preference should disable
+ * its dependents.
+ */
+ public void notifyDependencyChange(boolean disableDependents) {
+ final List<Preference> dependents = mDependents;
+
+ if (dependents == null) {
+ return;
+ }
+
+ final int dependentsCount = dependents.size();
+ for (int i = 0; i < dependentsCount; i++) {
+ dependents.get(i).onDependencyChanged(this, disableDependents);
+ }
+ }
+
+ /**
+ * Called when the dependency changes.
+ *
+ * @param dependency The Preference that this Preference depends on.
+ * @param disableDependent Set true to disable this Preference.
+ */
+ public void onDependencyChanged(Preference dependency, boolean disableDependent) {
+ if (mDependencyMet == disableDependent) {
+ mDependencyMet = !disableDependent;
+
+ // Enabled state can change dependent preferences' states, so notify
+ notifyDependencyChange(shouldDisableDependents());
+
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Called when the implicit parent dependency changes.
+ *
+ * @param parent The Preference that this Preference depends on.
+ * @param disableChild Set true to disable this Preference.
+ */
+ public void onParentChanged(Preference parent, boolean disableChild) {
+ if (mParentDependencyMet == disableChild) {
+ mParentDependencyMet = !disableChild;
+
+ // Enabled state can change dependent preferences' states, so notify
+ notifyDependencyChange(shouldDisableDependents());
+
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Checks whether this preference's dependents should currently be
+ * disabled.
+ *
+ * @return True if the dependents should be disabled, otherwise false.
+ */
+ public boolean shouldDisableDependents() {
+ return !isEnabled();
+ }
+
+ /**
+ * Sets the key of a Preference that this Preference will depend on. If that
+ * Preference is not set or is off, this Preference will be disabled.
+ *
+ * @param dependencyKey The key of the Preference that this depends on.
+ */
+ public void setDependency(String dependencyKey) {
+ // Unregister the old dependency, if we had one
+ unregisterDependency();
+
+ // Register the new
+ mDependencyKey = dependencyKey;
+ registerDependency();
+ }
+
+ /**
+ * Returns the key of the dependency on this Preference.
+ *
+ * @return The key of the dependency.
+ * @see #setDependency(String)
+ */
+ public String getDependency() {
+ return mDependencyKey;
+ }
+
+ /**
+ * Called when this Preference is being removed from the hierarchy. You
+ * should remove any references to this Preference that you know about. Make
+ * sure to call through to the superclass implementation.
+ */
+ protected void onPrepareForRemoval() {
+ unregisterDependency();
+ }
+
+ /**
+ * Sets the default value for this Preference, which will be set either if
+ * persistence is off or persistence is on and the preference is not found
+ * in the persistent storage.
+ *
+ * @param defaultValue The default value.
+ */
+ public void setDefaultValue(Object defaultValue) {
+ mDefaultValue = defaultValue;
+ }
+
+ private void dispatchSetInitialValue() {
+ // By now, we know if we are persistent.
+ final boolean shouldPersist = shouldPersist();
+ if (!shouldPersist || !getSharedPreferences().contains(mKey)) {
+ if (mDefaultValue != null) {
+ onSetInitialValue(false, mDefaultValue);
+ }
+ } else {
+ onSetInitialValue(true, null);
+ }
+ }
+
+ /**
+ * Implement this to set the initial value of the Preference.
+ * <p>
+ * If <var>restorePersistedValue</var> is true, you should restore the
+ * Preference value from the {@link android.content.SharedPreferences}. If
+ * <var>restorePersistedValue</var> is false, you should set the Preference
+ * value to defaultValue that is given (and possibly store to SharedPreferences
+ * if {@link #shouldPersist()} is true).
+ * <p>
+ * This may not always be called. One example is if it should not persist
+ * but there is no default value given.
+ *
+ * @param restorePersistedValue True to restore the persisted value;
+ * false to use the given <var>defaultValue</var>.
+ * @param defaultValue The default value for this Preference. Only use this
+ * if <var>restorePersistedValue</var> is false.
+ */
+ protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
+ }
+
+ private void tryCommit(@NonNull SharedPreferences.Editor editor) {
+ if (mPreferenceManager.shouldCommit()) {
+ SharedPreferencesCompat.EditorCompat.getInstance().apply(editor);
+ }
+ }
+
+ /**
+ * Attempts to persist a String to the {@link android.content.SharedPreferences}.
+ * <p>
+ * This will check if this Preference is persistent, get an editor from
+ * the {@link PreferenceManager}, put in the string, and check if we should commit (and
+ * commit if so).
+ *
+ * @param value The value to persist.
+ * @return True if the Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #getPersistedString(String)
+ */
+ protected boolean persistString(String value) {
+ if (shouldPersist()) {
+ // Shouldn't store null
+ if (value == getPersistedString(null)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = mPreferenceManager.getEditor();
+ editor.putString(mKey, value);
+ tryCommit(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
+ * <p>
+ * This will check if this Preference is persistent, get the SharedPreferences
+ * from the {@link PreferenceManager}, and get the value.
+ *
+ * @param defaultReturnValue The default value to return if either the
+ * Preference is not persistent or the Preference is not in the
+ * shared preferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #persistString(String)
+ */
+ protected String getPersistedString(String defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
+ }
+
+ /**
+ * Attempts to persist an int to the {@link android.content.SharedPreferences}.
+ *
+ * @param value The value to persist.
+ * @return True if the Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #persistString(String)
+ * @see #getPersistedInt(int)
+ */
+ protected boolean persistInt(int value) {
+ if (shouldPersist()) {
+ if (value == getPersistedInt(~value)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = mPreferenceManager.getEditor();
+ editor.putInt(mKey, value);
+ tryCommit(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
+ *
+ * @param defaultReturnValue The default value to return if either this
+ * Preference is not persistent or this Preference is not in the
+ * SharedPreferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #getPersistedString(String)
+ * @see #persistInt(int)
+ */
+ protected int getPersistedInt(int defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
+ }
+
+ /**
+ * Attempts to persist a float to the {@link android.content.SharedPreferences}.
+ *
+ * @param value The value to persist.
+ * @return True if this Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #persistString(String)
+ * @see #getPersistedFloat(float)
+ */
+ protected boolean persistFloat(float value) {
+ if (shouldPersist()) {
+ if (value == getPersistedFloat(Float.NaN)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = mPreferenceManager.getEditor();
+ editor.putFloat(mKey, value);
+ tryCommit(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
+ *
+ * @param defaultReturnValue The default value to return if either this
+ * Preference is not persistent or this Preference is not in the
+ * SharedPreferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #getPersistedString(String)
+ * @see #persistFloat(float)
+ */
+ protected float getPersistedFloat(float defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
+ }
+
+ /**
+ * Attempts to persist a long to the {@link android.content.SharedPreferences}.
+ *
+ * @param value The value to persist.
+ * @return True if this Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #persistString(String)
+ * @see #getPersistedLong(long)
+ */
+ protected boolean persistLong(long value) {
+ if (shouldPersist()) {
+ if (value == getPersistedLong(~value)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = mPreferenceManager.getEditor();
+ editor.putLong(mKey, value);
+ tryCommit(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
+ *
+ * @param defaultReturnValue The default value to return if either this
+ * Preference is not persistent or this Preference is not in the
+ * SharedPreferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #getPersistedString(String)
+ * @see #persistLong(long)
+ */
+ protected long getPersistedLong(long defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
+ }
+
+ /**
+ * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
+ *
+ * @param value The value to persist.
+ * @return True if this Preference is persistent. (This is not whether the
+ * value was persisted, since we may not necessarily commit if there
+ * will be a batch commit later.)
+ * @see #persistString(String)
+ * @see #getPersistedBoolean(boolean)
+ */
+ protected boolean persistBoolean(boolean value) {
+ if (shouldPersist()) {
+ if (value == getPersistedBoolean(!value)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ SharedPreferences.Editor editor = mPreferenceManager.getEditor();
+ editor.putBoolean(mKey, value);
+ tryCommit(editor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
+ *
+ * @param defaultReturnValue The default value to return if either this
+ * Preference is not persistent or this Preference is not in the
+ * SharedPreferences.
+ * @return The value from the SharedPreferences or the default return
+ * value.
+ * @see #getPersistedString(String)
+ * @see #persistBoolean(boolean)
+ */
+ protected boolean getPersistedBoolean(boolean defaultReturnValue) {
+ if (!shouldPersist()) {
+ return defaultReturnValue;
+ }
+
+ return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
+ }
+
+ @Override
+ public String toString() {
+ return getFilterableStringBuilder().toString();
+ }
+
+ /**
+ * Returns the text that will be used to filter this Preference depending on
+ * user input.
+ * <p>
+ * If overridding and calling through to the superclass, make sure to prepend
+ * your additions with a space.
+ *
+ * @return Text as a {@link StringBuilder} that will be used to filter this
+ * preference. By default, this is the title and summary
+ * (concatenated with a space).
+ */
+ StringBuilder getFilterableStringBuilder() {
+ StringBuilder sb = new StringBuilder();
+ CharSequence title = getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ sb.append(title).append(' ');
+ }
+ CharSequence summary = getSummary();
+ if (!TextUtils.isEmpty(summary)) {
+ sb.append(summary).append(' ');
+ }
+ if (sb.length() > 0) {
+ // Drop the last space
+ sb.setLength(sb.length() - 1);
+ }
+ return sb;
+ }
+
+ /**
+ * Store this Preference hierarchy's frozen state into the given container.
+ *
+ * @param container The Bundle in which to save the instance of this Preference.
+ *
+ * @see #restoreHierarchyState
+ * @see #onSaveInstanceState
+ */
+ public void saveHierarchyState(Bundle container) {
+ dispatchSaveInstanceState(container);
+ }
+
+ /**
+ * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children.
+ * May be overridden to modify how the save happens for children. For example, some
+ * Preference objects may want to not store an instance for their children.
+ *
+ * @param container The Bundle in which to save the instance of this Preference.
+ *
+ * @see #saveHierarchyState
+ * @see #onSaveInstanceState
+ */
+ void dispatchSaveInstanceState(Bundle container) {
+ if (hasKey()) {
+ mBaseMethodCalled = false;
+ Parcelable state = onSaveInstanceState();
+ if (!mBaseMethodCalled) {
+ throw new IllegalStateException(
+ "Derived class did not call super.onSaveInstanceState()");
+ }
+ if (state != null) {
+ container.putParcelable(mKey, state);
+ }
+ }
+ }
+
+ /**
+ * Hook allowing a Preference to generate a representation of its internal
+ * state that can later be used to create a new instance with that same
+ * state. This state should only contain information that is not persistent
+ * or can be reconstructed later.
+ *
+ * @return A Parcelable object containing the current dynamic state of
+ * this Preference, or null if there is nothing interesting to save.
+ * The default implementation returns null.
+ * @see #onRestoreInstanceState
+ * @see #saveHierarchyState
+ */
+ protected Parcelable onSaveInstanceState() {
+ mBaseMethodCalled = true;
+ return BaseSavedState.EMPTY_STATE;
+ }
+
+ /**
+ * Restore this Preference hierarchy's previously saved state from the given container.
+ *
+ * @param container The Bundle that holds the previously saved state.
+ *
+ * @see #saveHierarchyState
+ * @see #onRestoreInstanceState
+ */
+ public void restoreHierarchyState(Bundle container) {
+ dispatchRestoreInstanceState(container);
+ }
+
+ /**
+ * Called by {@link #restoreHierarchyState} to retrieve the saved state for this
+ * Preference and its children. May be overridden to modify how restoring
+ * happens to the children of a Preference. For example, some Preference objects may
+ * not want to save state for their children.
+ *
+ * @param container The Bundle that holds the previously saved state.
+ * @see #restoreHierarchyState
+ * @see #onRestoreInstanceState
+ */
+ void dispatchRestoreInstanceState(Bundle container) {
+ if (hasKey()) {
+ Parcelable state = container.getParcelable(mKey);
+ if (state != null) {
+ mBaseMethodCalled = false;
+ onRestoreInstanceState(state);
+ if (!mBaseMethodCalled) {
+ throw new IllegalStateException(
+ "Derived class did not call super.onRestoreInstanceState()");
+ }
+ }
+ }
+ }
+
+ /**
+ * Hook allowing a Preference to re-apply a representation of its internal
+ * state that had previously been generated by {@link #onSaveInstanceState}.
+ * This function will never be called with a null state.
+ *
+ * @param state The saved state that had previously been returned by
+ * {@link #onSaveInstanceState}.
+ * @see #onSaveInstanceState
+ * @see #restoreHierarchyState
+ */
+ protected void onRestoreInstanceState(Parcelable state) {
+ mBaseMethodCalled = true;
+ if (state != BaseSavedState.EMPTY_STATE && state != null) {
+ throw new IllegalArgumentException("Wrong state class -- expecting Preference State");
+ }
+ }
+
+ /**
+ * A base class for managing the instance state of a {@link Preference}.
+ */
+ public static class BaseSavedState extends AbsSavedState {
+ public BaseSavedState(Parcel source) {
+ super(source);
+ }
+
+ public BaseSavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<BaseSavedState> CREATOR =
+ new Parcelable.Creator<BaseSavedState>() {
+ public BaseSavedState createFromParcel(Parcel in) {
+ return new BaseSavedState(in);
+ }
+
+ public BaseSavedState[] newArray(int size) {
+ return new BaseSavedState[size];
+ }
+ };
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceCategory.java b/v7/preference/src/android/support/v7/preference/PreferenceCategory.java
new file mode 100644
index 0000000..bed7f7e
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceCategory.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * Used to group {@link android.preference.Preference} objects
+ * and provide a disabled title above the group.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about building a settings UI with Preferences,
+ * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
+ * guide.</p>
+ * </div>
+ */
+public class PreferenceCategory extends PreferenceGroup {
+ private static final String TAG = "PreferenceCategory";
+
+ public PreferenceCategory(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public PreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PreferenceCategory(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.preferenceCategoryStyle);
+ }
+
+ public PreferenceCategory(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ protected boolean onPrepareAddPreference(Preference preference) {
+ if (preference instanceof PreferenceCategory) {
+ throw new IllegalArgumentException(
+ "Cannot add a " + TAG + " directly to a " + TAG);
+ }
+
+ return super.onPrepareAddPreference(preference);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldDisableDependents() {
+ return !super.isEnabled();
+ }
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java
new file mode 100644
index 0000000..f96d2ce
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceDialogFragmentCompat.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+public abstract class PreferenceDialogFragmentCompat extends DialogFragment implements
+ DialogInterface.OnClickListener {
+
+ protected static final String ARG_KEY = "key";
+
+ private DialogPreference mPreference;
+
+ /** Which button was clicked. */
+ private int mWhichButtonClicked;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Fragment rawFragment = getTargetFragment();
+ if (!(rawFragment instanceof DialogPreference.TargetFragment)) {
+ throw new IllegalStateException("Target fragment must implement TargetFragment" +
+ " interface");
+ }
+
+ final DialogPreference.TargetFragment fragment =
+ (DialogPreference.TargetFragment) rawFragment;
+
+ final String key = getArguments().getString(ARG_KEY);
+ mPreference = (DialogPreference) fragment.findPreference(key);
+ }
+
+ @Override
+ public @NonNull Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+ mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ .setTitle(mPreference.getDialogTitle())
+ .setIcon(mPreference.getDialogIcon())
+ .setPositiveButton(mPreference.getPositiveButtonText(), this)
+ .setNegativeButton(mPreference.getNegativeButtonText(), this);
+
+ View contentView = onCreateDialogView(context);
+ if (contentView != null) {
+ onBindDialogView(contentView);
+ builder.setView(contentView);
+ } else {
+ builder.setMessage(mPreference.getDialogMessage());
+ }
+
+ onPrepareDialogBuilder(builder);
+
+ // Create the dialog
+ final Dialog dialog = builder.create();
+ if (needInputMethod()) {
+ requestInputMethod(dialog);
+ }
+
+
+ return builder.create();
+ }
+
+ /**
+ * Get the preference that requested this dialog. Available after {@link #onCreate(Bundle)} has
+ * been called.
+ *
+ * @return The {@link DialogPreference} associated with this
+ * dialog.
+ */
+ public DialogPreference getPreference() {
+ return mPreference;
+ }
+
+ /**
+ * Prepares the dialog builder to be shown when the preference is clicked.
+ * Use this to set custom properties on the dialog.
+ * <p>
+ * Do not {@link AlertDialog.Builder#create()} or
+ * {@link AlertDialog.Builder#show()}.
+ */
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {}
+
+ /**
+ * Returns whether the preference needs to display a soft input method when the dialog
+ * is displayed. Default is false. Subclasses should override this method if they need
+ * the soft input method brought up automatically.
+ * @hide
+ */
+ protected boolean needInputMethod() {
+ return false;
+ }
+
+ /**
+ * Sets the required flags on the dialog window to enable input method window to show up.
+ */
+ private void requestInputMethod(Dialog dialog) {
+ Window window = dialog.getWindow();
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ }
+
+ /**
+ * Creates the content view for the dialog (if a custom content view is
+ * required). By default, it inflates the dialog layout resource if it is
+ * set.
+ *
+ * @return The content View for the dialog.
+ * @see DialogPreference#setLayoutResource(int)
+ */
+ protected View onCreateDialogView(Context context) {
+ final int resId = mPreference.getDialogLayoutResource();
+ if (resId == 0) {
+ return null;
+ }
+
+ LayoutInflater inflater = LayoutInflater.from(context);
+ return inflater.inflate(resId, null);
+ }
+
+ /**
+ * Binds views in the content View of the dialog to data.
+ * <p>
+ * Make sure to call through to the superclass implementation.
+ *
+ * @param view The content View of the dialog, if it is custom.
+ */
+ protected void onBindDialogView(View view) {
+ View dialogMessageView = view.findViewById(android.R.id.message);
+
+ if (dialogMessageView != null) {
+ final CharSequence message = mPreference.getDialogMessage();
+ int newVisibility = View.GONE;
+
+ if (!TextUtils.isEmpty(message)) {
+ if (dialogMessageView instanceof TextView) {
+ ((TextView) dialogMessageView).setText(message);
+ }
+
+ newVisibility = View.VISIBLE;
+ }
+
+ if (dialogMessageView.getVisibility() != newVisibility) {
+ dialogMessageView.setVisibility(newVisibility);
+ }
+ }
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mWhichButtonClicked = which;
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
+ }
+
+ public abstract void onDialogClosed(boolean positiveResult);
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
new file mode 100644
index 0000000..adff8e8
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.Nullable;
+import android.support.annotation.XmlRes;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Shows a hierarchy of {@link Preference} objects as
+ * lists. These preferences will
+ * automatically save to {@link android.content.SharedPreferences} as the user interacts with
+ * them. To retrieve an instance of {@link android.content.SharedPreferences} that the
+ * preference hierarchy in this fragment will use, call
+ * {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)}
+ * with a context in the same package as this fragment.
+ * <p>
+ * Furthermore, the preferences shown will follow the visual style of system
+ * preferences. It is easy to create a hierarchy of preferences (that can be
+ * shown on multiple screens) via XML. For these reasons, it is recommended to
+ * use this fragment (as a superclass) to deal with preferences in applications.
+ * <p>
+ * A {@link PreferenceScreen} object should be at the top of the preference
+ * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
+ * denote a screen break--that is the preferences contained within subsequent
+ * {@link PreferenceScreen} should be shown on another screen. The preference
+ * framework handles showing these other screens from the preference hierarchy.
+ * <p>
+ * The preference hierarchy can be formed in multiple ways:
+ * <li> From an XML file specifying the hierarchy
+ * <li> From different {@link android.app.Activity Activities} that each specify its own
+ * preferences in an XML file via {@link android.app.Activity} meta-data
+ * <li> From an object hierarchy rooted with {@link PreferenceScreen}
+ * <p>
+ * To inflate from XML, use the {@link #addPreferencesFromResource(int)}. The
+ * root element should be a {@link PreferenceScreen}. Subsequent elements can point
+ * to actual {@link Preference} subclasses. As mentioned above, subsequent
+ * {@link PreferenceScreen} in the hierarchy will result in the screen break.
+ * <p>
+ * To specify an object hierarchy rooted with {@link PreferenceScreen}, use
+ * {@link #setPreferenceScreen(PreferenceScreen)}.
+ * <p>
+ * As a convenience, this fragment implements a click listener for any
+ * preference in the current hierarchy, see
+ * {@link #onPreferenceTreeClick(Preference)}.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about using {@code PreferenceFragment},
+ * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
+ * guide.</p>
+ * </div>
+ *
+ * <a name="SampleCode"></a>
+ * <h3>Sample Code</h3>
+ *
+ * <p>The following sample code shows a simple preference fragment that is
+ * populated from a resource. The resource it loads is:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/xml/preferences.xml preferences}
+ *
+ * <p>The fragment implementation itself simply populates the preferences
+ * when created. Note that the preferences framework takes care of loading
+ * the current values out of the app preferences and writing them when changed:</p>
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/FragmentPreferences.java
+ * fragment}
+ *
+ * @see Preference
+ * @see PreferenceScreen
+ */
+public abstract class PreferenceFragmentCompat extends Fragment implements
+ PreferenceManager.OnPreferenceTreeClickListener,
+ PreferenceManager.OnDisplayPreferenceDialogListener,
+ PreferenceManager.OnNavigateToScreenListener,
+ DialogPreference.TargetFragment {
+
+ /**
+ * Fragment argument used to specify the tag of the desired root
+ * {@link android.support.v7.preference.PreferenceScreen} object.
+ */
+ public static final String ARG_PREFERENCE_ROOT =
+ "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
+
+ private static final String PREFERENCES_TAG = "android:preferences";
+
+ private static final String DIALOG_FRAGMENT_TAG =
+ "android.support.v7.preference.PreferenceFragment.DIALOG";
+
+ private PreferenceManager mPreferenceManager;
+ private RecyclerView mList;
+ private boolean mHavePrefs;
+ private boolean mInitDone;
+
+ private Context mStyledContext;
+
+ private int mLayoutResId = R.layout.preference_list_fragment;
+
+ /**
+ * The starting request code given out to preference framework.
+ */
+ private static final int FIRST_REQUEST_CODE = 100;
+
+ private static final int MSG_BIND_PREFERENCES = 1;
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+
+ case MSG_BIND_PREFERENCES:
+ bindPreferences();
+ break;
+ }
+ }
+ };
+
+ final private Runnable mRequestFocus = new Runnable() {
+ public void run() {
+ mList.focusableViewAvailable(mList);
+ }
+ };
+
+ /**
+ * Interface that PreferenceFragment's containing activity should
+ * implement to be able to process preference items that wish to
+ * switch to a specified fragment.
+ */
+ public interface OnPreferenceStartFragmentCallback {
+ /**
+ * Called when the user has clicked on a Preference that has
+ * a fragment class name associated with it. The implementation
+ * should instantiate and switch to an instance of the given
+ * fragment.
+ * @param caller The fragment requesting navigation.
+ * @param pref The preference requesting the fragment.
+ * @return true if the fragment creation has been handled
+ */
+ boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref);
+ }
+
+ /**
+ * Interface that PreferenceFragment's containing activity should
+ * implement to be able to process preference items that wish to
+ * switch to a new screen of preferences.
+ */
+ public interface OnPreferenceStartScreenCallback {
+ /**
+ * Called when the user has clicked on a PreferenceScreen item in order to navigate to a new
+ * screen of preferences.
+ * @param caller The fragment requesting navigation.
+ * @param pref The preference screen to navigate to.
+ * @return true if the screen navigation has been handled
+ */
+ boolean onPreferenceStartScreen(PreferenceFragmentCompat caller, PreferenceScreen pref);
+ }
+
+ public interface OnPreferenceDisplayDialogCallback {
+
+ /**
+ *
+ * @param caller The fragment containing the preference requesting the dialog.
+ * @param pref The preference requesting the dialog.
+ * @return true if the dialog creation has been handled.
+ */
+ boolean onPreferenceDisplayDialog(PreferenceFragmentCompat caller, Preference pref);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final TypedValue tv = new TypedValue();
+ getActivity().getTheme().resolveAttribute(R.attr.preferenceTheme, tv, true);
+ final int theme = tv.resourceId;
+ if (theme <= 0) {
+ throw new IllegalStateException("Must specify preferenceTheme in theme");
+ }
+ mStyledContext = new ContextThemeWrapper(getActivity(), theme);
+
+ mPreferenceManager = new PreferenceManager(mStyledContext);
+ mPreferenceManager.setOnNavigateToScreenListener(this);
+ final Bundle args = getArguments();
+ final String rootKey;
+ if (args != null) {
+ rootKey = getArguments().getString(ARG_PREFERENCE_ROOT);
+ } else {
+ rootKey = null;
+ }
+ onCreatePreferences(savedInstanceState, rootKey);
+ }
+
+ /**
+ * Called during {@link #onCreate(Bundle)} to supply the preferences for this fragment.
+ * Subclasses are expected to call {@link #setPreferenceScreen(PreferenceScreen)} either
+ * directly or via helper methods such as {@link #addPreferencesFromResource(int)}.
+ *
+ * @param savedInstanceState If the fragment is being re-created from
+ * a previous saved state, this is the state.
+ * @param rootKey If non-null, this preference fragment should be rooted at the
+ * {@link android.support.v7.preference.PreferenceScreen} with this key.
+ */
+ public abstract void onCreatePreferences(Bundle savedInstanceState, String rootKey);
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ TypedArray a = mStyledContext.obtainStyledAttributes(null,
+ R.styleable.PreferenceFragmentCompat,
+ R.attr.preferenceFragmentStyle,
+ 0);
+
+ mLayoutResId = a.getResourceId(R.styleable.PreferenceFragmentCompat_layout,
+ mLayoutResId);
+
+ a.recycle();
+
+ final View view = inflater.inflate(mLayoutResId, container, false);
+
+ final View rawListContainer = view.findViewById(R.id.list_container);
+ if (!(rawListContainer instanceof ViewGroup)) {
+ throw new RuntimeException("Content has view with id attribute 'R.id.list_container' "
+ + "that is not a ViewGroup class");
+ }
+
+ final ViewGroup listContainer = (ViewGroup) rawListContainer;
+
+ final RecyclerView listView = onCreateRecyclerView(inflater, listContainer,
+ savedInstanceState);
+ if (listView == null) {
+ throw new RuntimeException("Could not create RecyclerView");
+ }
+
+ mList = listView;
+ listContainer.addView(mList);
+ mHandler.post(mRequestFocus);
+ return view;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (mHavePrefs) {
+ bindPreferences();
+ }
+
+ mInitDone = true;
+
+ if (savedInstanceState != null) {
+ Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
+ if (container != null) {
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ preferenceScreen.restoreHierarchyState(container);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mPreferenceManager.setOnPreferenceTreeClickListener(this);
+ mPreferenceManager.setOnDisplayPreferenceDialogListener(this);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mPreferenceManager.setOnPreferenceTreeClickListener(null);
+ mPreferenceManager.setOnDisplayPreferenceDialogListener(null);
+ }
+
+ @Override
+ public void onDestroyView() {
+ mList = null;
+ mHandler.removeCallbacks(mRequestFocus);
+ mHandler.removeMessages(MSG_BIND_PREFERENCES);
+ super.onDestroyView();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ Bundle container = new Bundle();
+ preferenceScreen.saveHierarchyState(container);
+ outState.putBundle(PREFERENCES_TAG, container);
+ }
+ }
+
+ /**
+ * Returns the {@link PreferenceManager} used by this fragment.
+ * @return The {@link PreferenceManager}.
+ */
+ public PreferenceManager getPreferenceManager() {
+ return mPreferenceManager;
+ }
+
+ /**
+ * Sets the root of the preference hierarchy that this fragment is showing.
+ *
+ * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
+ */
+ public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
+ if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
+ onUnbindPreferences();
+ mHavePrefs = true;
+ if (mInitDone) {
+ postBindPreferences();
+ }
+ }
+ }
+
+ /**
+ * Gets the root of the preference hierarchy that this fragment is showing.
+ *
+ * @return The {@link PreferenceScreen} that is the root of the preference
+ * hierarchy.
+ */
+ public PreferenceScreen getPreferenceScreen() {
+ return mPreferenceManager.getPreferenceScreen();
+ }
+
+ /**
+ * Inflates the given XML resource and adds the preference hierarchy to the current
+ * preference hierarchy.
+ *
+ * @param preferencesResId The XML resource ID to inflate.
+ */
+ public void addPreferencesFromResource(@XmlRes int preferencesResId) {
+ requirePreferenceManager();
+
+ setPreferenceScreen(mPreferenceManager.inflateFromResource(mStyledContext,
+ preferencesResId, getPreferenceScreen()));
+ }
+
+ /**
+ * Inflates the given XML resource and replaces the current preference hierarchy (if any) with
+ * the preference hierarchy rooted at {@code key}.
+ *
+ * @param preferencesResId The XML resource ID to inflate.
+ * @param key The preference key of the {@link android.support.v7.preference.PreferenceScreen}
+ * to use as the root of the preference hierarchy, or null to use the root
+ * {@link android.support.v7.preference.PreferenceScreen}.
+ */
+ public void setPreferencesFromResource(@XmlRes int preferencesResId, @Nullable String key) {
+ requirePreferenceManager();
+
+ final PreferenceScreen xmlRoot = mPreferenceManager.inflateFromResource(mStyledContext,
+ preferencesResId, null);
+
+ final Preference root;
+ if (key != null) {
+ root = xmlRoot.findPreference(key);
+ if (!(root instanceof PreferenceScreen)) {
+ throw new IllegalArgumentException("Preference object with key " + key
+ + " is not a PreferenceScreen");
+ }
+ } else {
+ root = xmlRoot;
+ }
+
+ setPreferenceScreen((PreferenceScreen) root);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean onPreferenceTreeClick(Preference preference) {
+ if (preference.getFragment() != null) {
+ boolean handled = false;
+ if (getTargetFragment() instanceof OnPreferenceStartFragmentCallback) {
+ handled = ((OnPreferenceStartFragmentCallback) getTargetFragment())
+ .onPreferenceStartFragment(this, preference);
+ }
+ if (!handled && getActivity() instanceof OnPreferenceStartFragmentCallback){
+ handled = ((OnPreferenceStartFragmentCallback) getActivity())
+ .onPreferenceStartFragment(this, preference);
+ }
+ return handled;
+ }
+ return false;
+ }
+
+ /**
+ * Called by
+ * {@link android.support.v7.preference.PreferenceScreen#onClick()} in order to navigate to a
+ * new screen of preferences. Calls
+ * {@link PreferenceFragmentCompat.OnPreferenceStartScreenCallback#onPreferenceStartScreen}
+ * if the target fragment or containing activity implements
+ * {@link PreferenceFragmentCompat.OnPreferenceStartScreenCallback}.
+ * @param preferenceScreen The {@link android.support.v7.preference.PreferenceScreen} to
+ * navigate to.
+ */
+ @Override
+ public void onNavigateToScreen(PreferenceScreen preferenceScreen) {
+ boolean handled = false;
+ if (getTargetFragment() instanceof OnPreferenceStartScreenCallback) {
+ handled = ((OnPreferenceStartScreenCallback) getTargetFragment())
+ .onPreferenceStartScreen(this, preferenceScreen);
+ }
+ if (!handled && getActivity() instanceof OnPreferenceStartScreenCallback) {
+ ((OnPreferenceStartScreenCallback) getActivity())
+ .onPreferenceStartScreen(this, preferenceScreen);
+ }
+ }
+
+ /**
+ * Finds a {@link Preference} based on its key.
+ *
+ * @param key The key of the preference to retrieve.
+ * @return The {@link Preference} with the key, or null.
+ * @see android.support.v7.preference.PreferenceGroup#findPreference(CharSequence)
+ */
+ public Preference findPreference(CharSequence key) {
+ if (mPreferenceManager == null) {
+ return null;
+ }
+ return mPreferenceManager.findPreference(key);
+ }
+
+ private void requirePreferenceManager() {
+ if (mPreferenceManager == null) {
+ throw new RuntimeException("This should be called after super.onCreate.");
+ }
+ }
+
+ private void postBindPreferences() {
+ if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
+ mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
+ }
+
+ private void bindPreferences() {
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ getListView().setAdapter(onCreateAdapter(preferenceScreen));
+ }
+ onBindPreferences();
+ }
+
+ /** @hide */
+ protected void onBindPreferences() {
+ }
+
+ /** @hide */
+ protected void onUnbindPreferences() {
+ }
+
+ public final RecyclerView getListView() {
+ return mList;
+ }
+
+ /**
+ * Creates the {@link android.support.v7.widget.RecyclerView} used to display the preferences.
+ * Subclasses may override this to return a customized
+ * {@link android.support.v7.widget.RecyclerView}.
+ * @param inflater The LayoutInflater object that can be used to inflate the
+ * {@link android.support.v7.widget.RecyclerView}.
+ * @param parent The parent {@link android.view.View} that the RecyclerView will be attached to.
+ * This method should not add the view itself, but this can be used to generate
+ * the LayoutParams of the view.
+ * @param savedInstanceState If non-null, this view is being re-constructed from a previous
+ * saved state as given here
+ * @return A new RecyclerView object to be placed into the view hierarchy
+ */
+ public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
+ Bundle savedInstanceState) {
+ RecyclerView recyclerView = (RecyclerView) inflater
+ .inflate(R.layout.preference_recyclerview, parent, false);
+
+ recyclerView.setLayoutManager(onCreateLayoutManager());
+
+ return recyclerView;
+ }
+
+ /**
+ * Called from {@link #onCreateRecyclerView} to create the
+ * {@link android.support.v7.widget.RecyclerView.LayoutManager} for the created
+ * {@link android.support.v7.widget.RecyclerView}.
+ * @return A new {@link android.support.v7.widget.RecyclerView.LayoutManager} instance.
+ */
+ public RecyclerView.LayoutManager onCreateLayoutManager() {
+ return new LinearLayoutManager(getActivity());
+ }
+
+ /**
+ * Creates the root adapter.
+ *
+ * @param preferenceScreen Preference screen object to create the adapter for.
+ * @return An adapter that contains the preferences contained in this {@link PreferenceScreen}.
+ */
+ protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
+ return new PreferenceGroupAdapter(preferenceScreen);
+ }
+
+ /**
+ * Called when a preference in the tree requests to display a dialog. Subclasses should
+ * override this method to display custom dialogs or to handle dialogs for custom preference
+ * classes.
+ *
+ * @param preference The Preference object requesting the dialog.
+ */
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+
+ boolean handled = false;
+ if (getTargetFragment() instanceof OnPreferenceDisplayDialogCallback) {
+ handled = ((OnPreferenceDisplayDialogCallback) getTargetFragment())
+ .onPreferenceDisplayDialog(this, preference);
+ }
+ if (!handled && getActivity() instanceof OnPreferenceDisplayDialogCallback) {
+ handled = ((OnPreferenceDisplayDialogCallback) getActivity())
+ .onPreferenceDisplayDialog(this, preference);
+ }
+
+ if (handled) {
+ return;
+ }
+
+ // check if dialog is already showing
+ if (getFragmentManager().findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {
+ return;
+ }
+
+ final DialogFragment f;
+ if (preference instanceof EditTextPreference) {
+ f = EditTextPreferenceDialogFragmentCompat.newInstance(preference.getKey());
+ } else if (preference instanceof ListPreference) {
+ f = ListPreferenceDialogFragmentCompat.newInstance(preference.getKey());
+ } else {
+ throw new IllegalArgumentException("Tried to display dialog for unknown " +
+ "preference type. Did you forget to override onDisplayPreferenceDialog()?");
+ }
+ f.setTargetFragment(this, 0);
+ f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroup.java b/v7/preference/src/android/support/v7/preference/PreferenceGroup.java
new file mode 100644
index 0000000..f1c79dd
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroup.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A container for multiple
+ * {@link Preference} objects. It is a base class for Preference objects that are
+ * parents, such as {@link PreferenceCategory} and {@link PreferenceScreen}.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about building a settings UI with Preferences,
+ * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
+ * guide.</p>
+ * </div>
+ *
+ * @attr ref android.R.styleable#PreferenceGroup_orderingFromXml
+ */
+public abstract class PreferenceGroup extends Preference {
+ /**
+ * The container for child {@link Preference}s. This is sorted based on the
+ * ordering, please use {@link #addPreference(Preference)} instead of adding
+ * to this directly.
+ */
+ private List<Preference> mPreferenceList;
+
+ private boolean mOrderingAsAdded = true;
+
+ private int mCurrentPreferenceOrder = 0;
+
+ private boolean mAttachedToActivity = false;
+
+ public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mPreferenceList = new ArrayList<>();
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.PreferenceGroup, defStyleAttr, defStyleRes);
+
+ mOrderingAsAdded =
+ TypedArrayUtils.getBoolean(a, R.styleable.PreferenceGroup_orderingFromXml,
+ R.styleable.PreferenceGroup_orderingFromXml, true);
+
+ a.recycle();
+ }
+
+ public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public PreferenceGroup(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ /**
+ * Whether to order the {@link Preference} children of this group as they
+ * are added. If this is false, the ordering will follow each Preference
+ * order and default to alphabetic for those without an order.
+ * <p>
+ * If this is called after preferences are added, they will not be
+ * re-ordered in the order they were added, hence call this method early on.
+ *
+ * @param orderingAsAdded Whether to order according to the order added.
+ * @see Preference#setOrder(int)
+ */
+ public void setOrderingAsAdded(boolean orderingAsAdded) {
+ mOrderingAsAdded = orderingAsAdded;
+ }
+
+ /**
+ * Whether this group is ordering preferences in the order they are added.
+ *
+ * @return Whether this group orders based on the order the children are added.
+ * @see #setOrderingAsAdded(boolean)
+ */
+ public boolean isOrderingAsAdded() {
+ return mOrderingAsAdded;
+ }
+
+ /**
+ * Called by the inflater to add an item to this group.
+ */
+ public void addItemFromInflater(Preference preference) {
+ addPreference(preference);
+ }
+
+ /**
+ * Returns the number of children {@link Preference}s.
+ * @return The number of preference children in this group.
+ */
+ public int getPreferenceCount() {
+ return mPreferenceList.size();
+ }
+
+ /**
+ * Returns the {@link Preference} at a particular index.
+ *
+ * @param index The index of the {@link Preference} to retrieve.
+ * @return The {@link Preference}.
+ */
+ public Preference getPreference(int index) {
+ return mPreferenceList.get(index);
+ }
+
+ /**
+ * Adds a {@link Preference} at the correct position based on the
+ * preference's order.
+ *
+ * @param preference The preference to add.
+ * @return Whether the preference is now in this group.
+ */
+ public boolean addPreference(Preference preference) {
+ if (mPreferenceList.contains(preference)) {
+ // Exists
+ return true;
+ }
+
+ if (preference.getOrder() == DEFAULT_ORDER) {
+ if (mOrderingAsAdded) {
+ preference.setOrder(mCurrentPreferenceOrder++);
+ }
+
+ if (preference instanceof PreferenceGroup) {
+ // TODO: fix (method is called tail recursively when inflating,
+ // so we won't end up properly passing this flag down to children
+ ((PreferenceGroup)preference).setOrderingAsAdded(mOrderingAsAdded);
+ }
+ }
+
+ int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
+ if (insertionIndex < 0) {
+ insertionIndex = insertionIndex * -1 - 1;
+ }
+
+ if (!onPrepareAddPreference(preference)) {
+ return false;
+ }
+
+ synchronized(this) {
+ mPreferenceList.add(insertionIndex, preference);
+ }
+
+ preference.onAttachedToHierarchy(getPreferenceManager());
+
+ if (mAttachedToActivity) {
+ preference.onAttached();
+ }
+
+ notifyHierarchyChanged();
+
+ return true;
+ }
+
+ /**
+ * Removes a {@link Preference} from this group.
+ *
+ * @param preference The preference to remove.
+ * @return Whether the preference was found and removed.
+ */
+ public boolean removePreference(Preference preference) {
+ final boolean returnValue = removePreferenceInt(preference);
+ notifyHierarchyChanged();
+ return returnValue;
+ }
+
+ private boolean removePreferenceInt(Preference preference) {
+ synchronized(this) {
+ preference.onPrepareForRemoval();
+ return mPreferenceList.remove(preference);
+ }
+ }
+
+ /**
+ * Removes all {@link Preference Preferences} from this group.
+ */
+ public void removeAll() {
+ synchronized(this) {
+ List<Preference> preferenceList = mPreferenceList;
+ for (int i = preferenceList.size() - 1; i >= 0; i--) {
+ removePreferenceInt(preferenceList.get(0));
+ }
+ }
+ notifyHierarchyChanged();
+ }
+
+ /**
+ * Prepares a {@link Preference} to be added to the group.
+ *
+ * @param preference The preference to add.
+ * @return Whether to allow adding the preference (true), or not (false).
+ */
+ protected boolean onPrepareAddPreference(Preference preference) {
+ preference.onParentChanged(this, shouldDisableDependents());
+ return true;
+ }
+
+ /**
+ * Finds a {@link Preference} based on its key. If two {@link Preference}
+ * share the same key (not recommended), the first to appear will be
+ * returned (to retrieve the other preference with the same key, call this
+ * method on the first preference). If this preference has the key, it will
+ * not be returned.
+ * <p>
+ * This will recursively search for the preference into children that are
+ * also {@link PreferenceGroup PreferenceGroups}.
+ *
+ * @param key The key of the preference to retrieve.
+ * @return The {@link Preference} with the key, or null.
+ */
+ public Preference findPreference(CharSequence key) {
+ if (TextUtils.equals(getKey(), key)) {
+ return this;
+ }
+ final int preferenceCount = getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ final Preference preference = getPreference(i);
+ final String curKey = preference.getKey();
+
+ if (curKey != null && curKey.equals(key)) {
+ return preference;
+ }
+
+ if (preference instanceof PreferenceGroup) {
+ final Preference returnedPreference = ((PreferenceGroup)preference)
+ .findPreference(key);
+ if (returnedPreference != null) {
+ return returnedPreference;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Whether this preference group should be shown on the same screen as its
+ * contained preferences.
+ *
+ * @return True if the contained preferences should be shown on the same
+ * screen as this preference.
+ */
+ protected boolean isOnSameScreenAsChildren() {
+ return true;
+ }
+
+ @Override
+ protected void onAttached() {
+ super.onAttached();
+
+ // Mark as attached so if a preference is later added to this group, we
+ // can tell it we are already attached
+ mAttachedToActivity = true;
+
+ // Dispatch to all contained preferences
+ final int preferenceCount = getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ getPreference(i).onAttached();
+ }
+ }
+
+ @Override
+ protected void onPrepareForRemoval() {
+ super.onPrepareForRemoval();
+
+ // We won't be attached to the activity anymore
+ mAttachedToActivity = false;
+ }
+
+ @Override
+ public void notifyDependencyChange(boolean disableDependents) {
+ super.notifyDependencyChange(disableDependents);
+
+ // Child preferences have an implicit dependency on their containing
+ // group. Dispatch dependency change to all contained preferences.
+ final int preferenceCount = getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ getPreference(i).onParentChanged(this, disableDependents);
+ }
+ }
+
+ void sortPreferences() {
+ synchronized (this) {
+ Collections.sort(mPreferenceList);
+ }
+ }
+
+ @Override
+ protected void dispatchSaveInstanceState(Bundle container) {
+ super.dispatchSaveInstanceState(container);
+
+ // Dispatch to all contained preferences
+ final int preferenceCount = getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ getPreference(i).dispatchSaveInstanceState(container);
+ }
+ }
+
+ @Override
+ protected void dispatchRestoreInstanceState(Bundle container) {
+ super.dispatchRestoreInstanceState(container);
+
+ // Dispatch to all contained preferences
+ final int preferenceCount = getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ getPreference(i).dispatchRestoreInstanceState(container);
+ }
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
new file mode 100644
index 0000000..5ba0f90
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.os.Handler;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An adapter that connects a RecyclerView to the {@link Preference} objects contained in the
+ * associated {@link PreferenceGroup}.
+ *
+ * @hide
+ */
+public class PreferenceGroupAdapter extends RecyclerView.Adapter<PreferenceViewHolder>
+ implements Preference.OnPreferenceChangeInternalListener {
+
+ private static final String TAG = "PreferenceGroupAdapter";
+
+ /**
+ * The group that we are providing data from.
+ */
+ private PreferenceGroup mPreferenceGroup;
+
+ /**
+ * Maps a position into this adapter -> {@link Preference}. These
+ * {@link Preference}s don't have to be direct children of this
+ * {@link PreferenceGroup}, they can be grand children or younger)
+ */
+ private List<Preference> mPreferenceList;
+
+ /**
+ * Contains a sorted list of all preferences in this adapter regardless of visibility. This is
+ * used to construct {@link #mPreferenceList}
+ */
+ private List<Preference> mPreferenceListInternal;
+
+ /**
+ * List of unique Preference and its subclasses' names and layouts.
+ */
+ private List<PreferenceLayout> mPreferenceLayouts;
+
+
+ private PreferenceLayout mTempPreferenceLayout = new PreferenceLayout();
+
+ private volatile boolean mIsSyncing = false;
+
+ private Handler mHandler = new Handler();
+
+ private Runnable mSyncRunnable = new Runnable() {
+ public void run() {
+ syncMyPreferences();
+ }
+ };
+
+ private static class PreferenceLayout {
+ private int resId;
+ private int widgetResId;
+ private String name;
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof PreferenceLayout)) {
+ return false;
+ }
+ final PreferenceLayout other = (PreferenceLayout) o;
+ return resId == other.resId
+ && widgetResId == other.widgetResId
+ && TextUtils.equals(name, other.name);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + resId;
+ result = 31 * result + widgetResId;
+ result = 31 * result + name.hashCode();
+ return result;
+ }
+ }
+
+ public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
+ mPreferenceGroup = preferenceGroup;
+ // If this group gets or loses any children, let us know
+ mPreferenceGroup.setOnPreferenceChangeInternalListener(this);
+
+ mPreferenceList = new ArrayList<>();
+ mPreferenceListInternal = new ArrayList<>();
+ mPreferenceLayouts = new ArrayList<>();
+
+ setHasStableIds(true);
+
+ syncMyPreferences();
+ }
+
+ private void syncMyPreferences() {
+ synchronized(this) {
+ if (mIsSyncing) {
+ return;
+ }
+
+ mIsSyncing = true;
+ }
+
+ List<Preference> newPreferenceList = new ArrayList<>(mPreferenceListInternal.size());
+ flattenPreferenceGroup(newPreferenceList, mPreferenceGroup);
+ mPreferenceListInternal = newPreferenceList;
+
+ mPreferenceList = new ArrayList<>(mPreferenceListInternal.size());
+ // Copy only the visible preferences to the active list
+ for (final Preference preference : mPreferenceListInternal) {
+ if (preference.isVisible()) {
+ mPreferenceList.add(preference);
+ }
+ }
+
+ notifyDataSetChanged();
+
+ synchronized(this) {
+ mIsSyncing = false;
+ notifyAll();
+ }
+ }
+
+ private void flattenPreferenceGroup(List<Preference> preferences, PreferenceGroup group) {
+ group.sortPreferences();
+
+ final int groupSize = group.getPreferenceCount();
+ for (int i = 0; i < groupSize; i++) {
+ final Preference preference = group.getPreference(i);
+
+ preferences.add(preference);
+
+ addPreferenceClassName(preference);
+
+ if (preference instanceof PreferenceGroup) {
+ final PreferenceGroup preferenceAsGroup = (PreferenceGroup) preference;
+ if (preferenceAsGroup.isOnSameScreenAsChildren()) {
+ flattenPreferenceGroup(preferences, preferenceAsGroup);
+ }
+ }
+
+ preference.setOnPreferenceChangeInternalListener(this);
+ }
+ }
+
+ /**
+ * Creates a string that includes the preference name, layout id and widget layout id.
+ * If a particular preference type uses 2 different resources, they will be treated as
+ * different view types.
+ */
+ private PreferenceLayout createPreferenceLayout(Preference preference, PreferenceLayout in) {
+ PreferenceLayout pl = in != null? in : new PreferenceLayout();
+ pl.name = preference.getClass().getName();
+ pl.resId = preference.getLayoutResource();
+ pl.widgetResId = preference.getWidgetLayoutResource();
+ return pl;
+ }
+
+ private void addPreferenceClassName(Preference preference) {
+ final PreferenceLayout pl = createPreferenceLayout(preference, null);
+ if (!mPreferenceLayouts.contains(pl)) {
+ mPreferenceLayouts.add(pl);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mPreferenceList.size();
+ }
+
+ public Preference getItem(int position) {
+ if (position < 0 || position >= getItemCount()) return null;
+ return mPreferenceList.get(position);
+ }
+
+ public long getItemId(int position) {
+ if (position < 0 || position >= getItemCount()) return ListView.INVALID_ROW_ID;
+ return this.getItem(position).getId();
+ }
+
+ public void onPreferenceChange(Preference preference) {
+ notifyDataSetChanged();
+ }
+
+ public void onPreferenceHierarchyChange(Preference preference) {
+ mHandler.removeCallbacks(mSyncRunnable);
+ mHandler.post(mSyncRunnable);
+ }
+
+ @Override
+ public void onPreferenceVisibilityChange(Preference preference) {
+ if (preference.isVisible()) {
+ // The preference has become visible, we need to add it in the correct location.
+
+ // Index (inferred) in mPreferenceList of the item preceding the newly visible pref
+ int previousVisibleIndex = -1;
+ for (final Preference pref : mPreferenceListInternal) {
+ if (preference.equals(pref)) {
+ break;
+ }
+ if (pref.isVisible()) {
+ previousVisibleIndex++;
+ }
+ }
+ // Insert this preference into the active list just after the previous visible entry
+ mPreferenceList.add(previousVisibleIndex + 1, preference);
+
+ notifyItemInserted(previousVisibleIndex + 1);
+ } else {
+ // The preference has become invisibile. Find it in the list and remove it.
+
+ int removalIndex;
+ final int listSize = mPreferenceList.size();
+ for (removalIndex = 0; removalIndex < listSize; removalIndex++) {
+ if (preference.equals(mPreferenceList.get(removalIndex))) {
+ break;
+ }
+ }
+ mPreferenceList.remove(removalIndex);
+ notifyItemRemoved(removalIndex);
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ final Preference preference = this.getItem(position);
+
+ mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout);
+
+ return mPreferenceLayouts.indexOf(mTempPreferenceLayout);
+ }
+
+ @Override
+ public PreferenceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final PreferenceLayout pl = mPreferenceLayouts.get(viewType);
+ final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+
+ final ViewGroup view = (ViewGroup) inflater.inflate(pl.resId, parent, false);
+
+ final ViewGroup widgetFrame = (ViewGroup) view.findViewById(R.id.widget_frame);
+ if (widgetFrame != null) {
+ if (pl.widgetResId != 0) {
+ inflater.inflate(pl.widgetResId, widgetFrame);
+ } else {
+ widgetFrame.setVisibility(View.GONE);
+ }
+ }
+
+ return new PreferenceViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder, int position) {
+ final Preference preference = getItem(position);
+ preference.onBindViewHolder(holder);
+ }
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceInflater.java b/v7/preference/src/android/support/v7/preference/PreferenceInflater.java
new file mode 100644
index 0000000..fa4e29f
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceInflater.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.InflateException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
+/**
+ * The {@link PreferenceInflater} is used to inflate preference hierarchies from
+ * XML files.
+ */
+class PreferenceInflater {
+ private static final String TAG = "PreferenceInflater";
+
+ private static final Class<?>[] CONSTRUCTOR_SIGNATURE = new Class[] {
+ Context.class, AttributeSet.class};
+
+ private static final HashMap<String, Constructor> CONSTRUCTOR_MAP = new HashMap<>();
+
+ private final Context mContext;
+
+ private final Object[] mConstructorArgs = new Object[2];
+
+ private PreferenceManager mPreferenceManager;
+
+ private String[] mDefaultPackages;
+
+ private static final String INTENT_TAG_NAME = "intent";
+ private static final String EXTRA_TAG_NAME = "extra";
+
+ public PreferenceInflater(Context context, PreferenceManager preferenceManager) {
+ mContext = context;
+ init(preferenceManager);
+ }
+
+ private void init(PreferenceManager preferenceManager) {
+ mPreferenceManager = preferenceManager;
+ if (Build.VERSION.SDK_INT >= 14) {
+ setDefaultPackages(new String[] {"android.support.v14.preference.",
+ "android.support.v7.preference."});
+ } else {
+ setDefaultPackages(new String[] {"android.support.v7.preference."});
+ }
+ }
+
+ /**
+ * Sets the default package that will be searched for classes to construct
+ * for tag names that have no explicit package.
+ *
+ * @param defaultPackage The default package. This will be prepended to the
+ * tag name, so it should end with a period.
+ */
+ public void setDefaultPackages(String[] defaultPackage) {
+ mDefaultPackages = defaultPackage;
+ }
+
+ /**
+ * Returns the default package, or null if it is not set.
+ *
+ * @see #setDefaultPackages(String[])
+ * @return The default package.
+ */
+ public String[] getDefaultPackages() {
+ return mDefaultPackages;
+ }
+
+ /**
+ * Return the context we are running in, for access to resources, class
+ * loader, etc.
+ */
+ public Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Inflate a new item hierarchy from the specified xml resource. Throws
+ * InflaterException if there is an error.
+ *
+ * @param resource ID for an XML resource to load (e.g.,
+ * <code>R.layout.main_page</code>)
+ * @param root Optional parent of the generated hierarchy.
+ * @return The root of the inflated hierarchy. If root was supplied,
+ * this is the root item; otherwise it is the root of the inflated
+ * XML file.
+ */
+ public Preference inflate(int resource, @Nullable PreferenceGroup root) {
+ XmlResourceParser parser = getContext().getResources().getXml(resource);
+ try {
+ return inflate(parser, root);
+ } finally {
+ parser.close();
+ }
+ }
+
+ /**
+ * Inflate a new hierarchy from the specified XML node. Throws
+ * InflaterException if there is an error.
+ * <p>
+ * <em><strong>Important</strong></em> For performance
+ * reasons, inflation relies heavily on pre-processing of XML files
+ * that is done at build time. Therefore, it is not currently possible to
+ * use inflater with an XmlPullParser over a plain XML file at runtime.
+ *
+ * @param parser XML dom node containing the description of the
+ * hierarchy.
+ * @param root Optional to be the parent of the generated hierarchy (if
+ * <em>attachToRoot</em> is true), or else simply an object that
+ * provides a set of values for root of the returned
+ * hierarchy (if <em>attachToRoot</em> is false.)
+ * @return The root of the inflated hierarchy. If root was supplied,
+ * this is root; otherwise it is the root of
+ * the inflated XML file.
+ */
+ public Preference inflate(XmlPullParser parser, @Nullable PreferenceGroup root) {
+ synchronized (mConstructorArgs) {
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ mConstructorArgs[0] = mContext;
+ final Preference result;
+
+ try {
+ // Look for the root node.
+ int type;
+ do {
+ type = parser.next();
+ } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(parser.getPositionDescription()
+ + ": No start tag found!");
+ }
+
+ // Temp is the root that was found in the xml
+ Preference xmlRoot = createItemFromTag(parser.getName(),
+ attrs);
+
+ result = onMergeRoots(root, (PreferenceGroup) xmlRoot);
+
+ // Inflate all children under temp
+ rInflate(parser, result, attrs);
+
+ } catch (InflateException e) {
+ throw e;
+ } catch (XmlPullParserException e) {
+ final InflateException ex = new InflateException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } catch (IOException e) {
+ final InflateException ex = new InflateException(
+ parser.getPositionDescription()
+ + ": " + e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+
+ return result;
+ }
+ }
+
+ private @NonNull PreferenceGroup onMergeRoots(PreferenceGroup givenRoot,
+ @NonNull PreferenceGroup xmlRoot) {
+ // If we were given a Preferences, use it as the root (ignoring the root
+ // Preferences from the XML file).
+ if (givenRoot == null) {
+ xmlRoot.onAttachedToHierarchy(mPreferenceManager);
+ return xmlRoot;
+ } else {
+ return givenRoot;
+ }
+ }
+
+ /**
+ * Low-level function for instantiating by name. This attempts to
+ * instantiate class of the given <var>name</var> found in this
+ * inflater's ClassLoader.
+ *
+ * <p>
+ * There are two things that can happen in an error case: either the
+ * exception describing the error will be thrown, or a null will be
+ * returned. You must deal with both possibilities -- the former will happen
+ * the first time createItem() is called for a class of a particular name,
+ * the latter every time there-after for that class name.
+ *
+ * @param name The full name of the class to be instantiated.
+ * @param attrs The XML attributes supplied for this instance.
+ *
+ * @return The newly instantied item, or null.
+ */
+ private Preference createItem(@NonNull String name, @Nullable String[] prefixes,
+ AttributeSet attrs)
+ throws ClassNotFoundException, InflateException {
+ Constructor constructor = CONSTRUCTOR_MAP.get(name);
+
+ try {
+ if (constructor == null) {
+ // Class not found in the cache, see if it's real,
+ // and try to add it
+ final ClassLoader classLoader = mContext.getClassLoader();
+ Class<?> clazz = null;
+ if (prefixes == null || prefixes.length == 0) {
+ clazz = classLoader.loadClass(name);
+ } else {
+ ClassNotFoundException notFoundException = null;
+ for (final String prefix : prefixes) {
+ try {
+ clazz = classLoader.loadClass(prefix + name);
+ } catch (final ClassNotFoundException e) {
+ notFoundException = e;
+ }
+ }
+ if (clazz == null) {
+ if (notFoundException == null) {
+ throw new InflateException(attrs
+ .getPositionDescription()
+ + ": Error inflating class " + name);
+ } else {
+ throw notFoundException;
+ }
+ }
+ }
+ constructor = clazz.getConstructor(CONSTRUCTOR_SIGNATURE);
+ constructor.setAccessible(true);
+ CONSTRUCTOR_MAP.put(name, constructor);
+ }
+
+ Object[] args = mConstructorArgs;
+ args[1] = attrs;
+ return (Preference) constructor.newInstance(args);
+
+ } catch (ClassNotFoundException e) {
+ // If loadClass fails, we should propagate the exception.
+ throw e;
+ } catch (Exception e) {
+ final InflateException ie = new InflateException(attrs
+ .getPositionDescription() + ": Error inflating class " + name);
+ ie.initCause(e);
+ throw ie;
+ }
+ }
+
+ /**
+ * This routine is responsible for creating the correct subclass of item
+ * given the xml element name. Override it to handle custom item objects. If
+ * you override this in your subclass be sure to call through to
+ * super.onCreateItem(name) for names you do not recognize.
+ *
+ * @param name The fully qualified class name of the item to be create.
+ * @param attrs An AttributeSet of attributes to apply to the item.
+ * @return The item created.
+ */
+ protected Preference onCreateItem(String name, AttributeSet attrs)
+ throws ClassNotFoundException {
+ return createItem(name, mDefaultPackages, attrs);
+ }
+
+ private Preference createItemFromTag(String name,
+ AttributeSet attrs) {
+ try {
+ final Preference item;
+
+ if (-1 == name.indexOf('.')) {
+ item = onCreateItem(name, attrs);
+ } else {
+ item = createItem(name, null, attrs);
+ }
+
+ return item;
+
+ } catch (InflateException e) {
+ throw e;
+
+ } catch (ClassNotFoundException e) {
+ final InflateException ie = new InflateException(attrs
+ .getPositionDescription()
+ + ": Error inflating class (not found)" + name);
+ ie.initCause(e);
+ throw ie;
+
+ } catch (Exception e) {
+ final InflateException ie = new InflateException(attrs
+ .getPositionDescription()
+ + ": Error inflating class " + name);
+ ie.initCause(e);
+ throw ie;
+ }
+ }
+
+ /**
+ * Recursive method used to descend down the xml hierarchy and instantiate
+ * items, instantiate their children, and then call onFinishInflate().
+ */
+ private void rInflate(XmlPullParser parser, Preference parent, final AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ final int depth = parser.getDepth();
+
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final String name = parser.getName();
+
+ if (INTENT_TAG_NAME.equals(name)) {
+ final Intent intent;
+
+ try {
+ intent = Intent.parseIntent(getContext().getResources(), parser, attrs);
+ } catch (IOException e) {
+ XmlPullParserException ex = new XmlPullParserException(
+ "Error parsing preference");
+ ex.initCause(e);
+ throw ex;
+ }
+
+ parent.setIntent(intent);
+ } else if (EXTRA_TAG_NAME.equals(name)) {
+ getContext().getResources().parseBundleExtra(EXTRA_TAG_NAME, attrs,
+ parent.getExtras());
+ try {
+ skipCurrentTag(parser);
+ } catch (IOException e) {
+ XmlPullParserException ex = new XmlPullParserException(
+ "Error parsing preference");
+ ex.initCause(e);
+ throw ex;
+ }
+ } else {
+ final Preference item = createItemFromTag(name, attrs);
+ ((PreferenceGroup) parent).addItemFromInflater(item);
+ rInflate(parser, item, attrs);
+ }
+ }
+
+ }
+
+ private static void skipCurrentTag(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ do {
+ type = parser.next();
+ } while (type != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth));
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceManager.java b/v7/preference/src/android/support/v7/preference/PreferenceManager.java
new file mode 100644
index 0000000..7e8c5d1
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceManager.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.v4.content.SharedPreferencesCompat;
+
+/**
+ * Used to help create {@link Preference} hierarchies
+ * from activities or XML.
+ * <p>
+ * In most cases, clients should use
+ * {@link PreferenceFragment#addPreferencesFromResource(int)}, or
+ * {@link PreferenceFragmentCompat#addPreferencesFromResource(int)}.
+ *
+ * @see PreferenceFragment
+ * @see PreferenceFragmentCompat
+ */
+public class PreferenceManager {
+
+ private static final String TAG = "PreferenceManager";
+
+ public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+
+ /**
+ * The context to use. This should always be set.
+ */
+ private Context mContext;
+
+ /**
+ * The counter for unique IDs.
+ */
+ private long mNextId = 0;
+
+ /**
+ * Cached shared preferences.
+ */
+ private SharedPreferences mSharedPreferences;
+
+ /**
+ * If in no-commit mode, the shared editor to give out (which will be
+ * committed when exiting no-commit mode).
+ */
+ private SharedPreferences.Editor mEditor;
+
+ /**
+ * Blocks commits from happening on the shared editor. This is used when
+ * inflating the hierarchy. Do not set this directly, use {@link #setNoCommit(boolean)}
+ */
+ private boolean mNoCommit;
+
+ /**
+ * The SharedPreferences name that will be used for all {@link Preference}s
+ * managed by this instance.
+ */
+ private String mSharedPreferencesName;
+
+ /**
+ * The SharedPreferences mode that will be used for all {@link Preference}s
+ * managed by this instance.
+ */
+ private int mSharedPreferencesMode;
+
+ /**
+ * The {@link PreferenceScreen} at the root of the preference hierarchy.
+ */
+ private PreferenceScreen mPreferenceScreen;
+
+ private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
+ private OnDisplayPreferenceDialogListener mOnDisplayPreferenceDialogListener;
+ private OnNavigateToScreenListener mOnNavigateToScreenListener;
+
+ /**
+ * @hide
+ */
+ public PreferenceManager(Context context) {
+ mContext = context;
+
+ setSharedPreferencesName(getDefaultSharedPreferencesName(context));
+ }
+
+ /**
+ * Inflates a preference hierarchy from XML. If a preference hierarchy is
+ * given, the new preference hierarchies will be merged in.
+ *
+ * @param context The context of the resource.
+ * @param resId The resource ID of the XML to inflate.
+ * @param rootPreferences Optional existing hierarchy to merge the new
+ * hierarchies into.
+ * @return The root hierarchy (if one was not provided, the new hierarchy's
+ * root).
+ * @hide
+ */
+ public PreferenceScreen inflateFromResource(Context context, int resId,
+ PreferenceScreen rootPreferences) {
+ // Block commits
+ setNoCommit(true);
+
+ final PreferenceInflater inflater = new PreferenceInflater(context, this);
+ rootPreferences = (PreferenceScreen) inflater.inflate(resId, rootPreferences);
+ rootPreferences.onAttachedToHierarchy(this);
+
+ // Unblock commits
+ setNoCommit(false);
+
+ return rootPreferences;
+ }
+
+ public PreferenceScreen createPreferenceScreen(Context context) {
+ final PreferenceScreen preferenceScreen = new PreferenceScreen(context, null);
+ preferenceScreen.onAttachedToHierarchy(this);
+ return preferenceScreen;
+ }
+
+ /**
+ * Called by a preference to get a unique ID in its hierarchy.
+ *
+ * @return A unique ID.
+ */
+ long getNextId() {
+ synchronized (this) {
+ return mNextId++;
+ }
+ }
+
+ /**
+ * Returns the current name of the SharedPreferences file that preferences managed by
+ * this will use.
+ *
+ * @return The name that can be passed to {@link Context#getSharedPreferences(String, int)}.
+ * @see Context#getSharedPreferences(String, int)
+ */
+ public String getSharedPreferencesName() {
+ return mSharedPreferencesName;
+ }
+
+ /**
+ * Sets the name of the SharedPreferences file that preferences managed by this
+ * will use.
+ *
+ * @param sharedPreferencesName The name of the SharedPreferences file.
+ * @see Context#getSharedPreferences(String, int)
+ */
+ public void setSharedPreferencesName(String sharedPreferencesName) {
+ mSharedPreferencesName = sharedPreferencesName;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Returns the current mode of the SharedPreferences file that preferences managed by
+ * this will use.
+ *
+ * @return The mode that can be passed to {@link Context#getSharedPreferences(String, int)}.
+ * @see Context#getSharedPreferences(String, int)
+ */
+ public int getSharedPreferencesMode() {
+ return mSharedPreferencesMode;
+ }
+
+ /**
+ * Sets the mode of the SharedPreferences file that preferences managed by this
+ * will use.
+ *
+ * @param sharedPreferencesMode The mode of the SharedPreferences file.
+ * @see Context#getSharedPreferences(String, int)
+ */
+ public void setSharedPreferencesMode(int sharedPreferencesMode) {
+ mSharedPreferencesMode = sharedPreferencesMode;
+ mSharedPreferences = null;
+ }
+
+ /**
+ * Gets a SharedPreferences instance that preferences managed by this will
+ * use.
+ *
+ * @return A SharedPreferences instance pointing to the file that contains
+ * the values of preferences that are managed by this.
+ */
+ public SharedPreferences getSharedPreferences() {
+ if (mSharedPreferences == null) {
+ mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
+ mSharedPreferencesMode);
+ }
+
+ return mSharedPreferences;
+ }
+
+ /**
+ * Gets a SharedPreferences instance that points to the default file that is
+ * used by the preference framework in the given context.
+ *
+ * @param context The context of the preferences whose values are wanted.
+ * @return A SharedPreferences instance that can be used to retrieve and
+ * listen to values of the preferences.
+ */
+ public static SharedPreferences getDefaultSharedPreferences(Context context) {
+ return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
+ getDefaultSharedPreferencesMode());
+ }
+
+ private static String getDefaultSharedPreferencesName(Context context) {
+ return context.getPackageName() + "_preferences";
+ }
+
+ private static int getDefaultSharedPreferencesMode() {
+ return Context.MODE_PRIVATE;
+ }
+
+ /**
+ * Returns the root of the preference hierarchy managed by this class.
+ *
+ * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
+ */
+ public PreferenceScreen getPreferenceScreen() {
+ return mPreferenceScreen;
+ }
+
+ /**
+ * Sets the root of the preference hierarchy.
+ *
+ * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
+ * @return Whether the {@link PreferenceScreen} given is different than the previous.
+ */
+ public boolean setPreferences(PreferenceScreen preferenceScreen) {
+ if (preferenceScreen != mPreferenceScreen) {
+ mPreferenceScreen = preferenceScreen;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Finds a {@link Preference} based on its key.
+ *
+ * @param key The key of the preference to retrieve.
+ * @return The {@link Preference} with the key, or null.
+ * @see PreferenceGroup#findPreference(CharSequence)
+ */
+ public Preference findPreference(CharSequence key) {
+ if (mPreferenceScreen == null) {
+ return null;
+ }
+
+ return mPreferenceScreen.findPreference(key);
+ }
+
+ /**
+ * Sets the default values from an XML preference file by reading the values defined
+ * by each {@link Preference} item's {@code android:defaultValue} attribute. This should
+ * be called by the application's main activity.
+ * <p>
+ *
+ * @param context The context of the shared preferences.
+ * @param resId The resource ID of the preference XML file.
+ * @param readAgain Whether to re-read the default values.
+ * If false, this method sets the default values only if this
+ * method has never been called in the past (or if the
+ * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
+ * preferences file is false). To attempt to set the default values again
+ * bypassing this check, set {@code readAgain} to true.
+ * <p class="note">
+ * Note: this will NOT reset preferences back to their default
+ * values. For that functionality, use
+ * {@link PreferenceManager#getDefaultSharedPreferences(Context)}
+ * and clear it followed by a call to this method with this
+ * parameter set to true.
+ */
+ public static void setDefaultValues(Context context, int resId, boolean readAgain) {
+
+ // Use the default shared preferences name and mode
+ setDefaultValues(context, getDefaultSharedPreferencesName(context),
+ getDefaultSharedPreferencesMode(), resId, readAgain);
+ }
+
+ /**
+ * Similar to {@link #setDefaultValues(Context, int, boolean)} but allows
+ * the client to provide the filename and mode of the shared preferences
+ * file.
+ *
+ * @param context The context of the shared preferences.
+ * @param sharedPreferencesName A custom name for the shared preferences file.
+ * @param sharedPreferencesMode The file creation mode for the shared preferences file, such
+ * as {@link android.content.Context#MODE_PRIVATE} or {@link
+ * android.content.Context#MODE_PRIVATE}
+ * @param resId The resource ID of the preference XML file.
+ * @param readAgain Whether to re-read the default values.
+ * If false, this method will set the default values only if this
+ * method has never been called in the past (or if the
+ * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
+ * preferences file is false). To attempt to set the default values again
+ * bypassing this check, set {@code readAgain} to true.
+ * <p class="note">
+ * Note: this will NOT reset preferences back to their default
+ * values. For that functionality, use
+ * {@link PreferenceManager#getDefaultSharedPreferences(Context)}
+ * and clear it followed by a call to this method with this
+ * parameter set to true.
+ *
+ * @see #setDefaultValues(Context, int, boolean)
+ * @see #setSharedPreferencesName(String)
+ * @see #setSharedPreferencesMode(int)
+ */
+ public static void setDefaultValues(Context context, String sharedPreferencesName,
+ int sharedPreferencesMode, int resId, boolean readAgain) {
+ final SharedPreferences defaultValueSp = context.getSharedPreferences(
+ KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
+
+ if (readAgain || !defaultValueSp.getBoolean(KEY_HAS_SET_DEFAULT_VALUES, false)) {
+ final PreferenceManager pm = new PreferenceManager(context);
+ pm.setSharedPreferencesName(sharedPreferencesName);
+ pm.setSharedPreferencesMode(sharedPreferencesMode);
+ pm.inflateFromResource(context, resId, null);
+
+ SharedPreferences.Editor editor =
+ defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
+
+ SharedPreferencesCompat.EditorCompat.getInstance().apply(editor);
+ }
+ }
+
+ /**
+ * Returns an editor to use when modifying the shared preferences.
+ * <p>
+ * Do NOT commit unless {@link #shouldCommit()} returns true.
+ *
+ * @return An editor to use to write to shared preferences.
+ * @see #shouldCommit()
+ */
+ SharedPreferences.Editor getEditor() {
+
+ if (mNoCommit) {
+ if (mEditor == null) {
+ mEditor = getSharedPreferences().edit();
+ }
+
+ return mEditor;
+ } else {
+ return getSharedPreferences().edit();
+ }
+ }
+
+ /**
+ * Whether it is the client's responsibility to commit on the
+ * {@link #getEditor()}. This will return false in cases where the writes
+ * should be batched, for example when inflating preferences from XML.
+ *
+ * @return Whether the client should commit.
+ */
+ boolean shouldCommit() {
+ return !mNoCommit;
+ }
+
+ private void setNoCommit(boolean noCommit) {
+ if (!noCommit && mEditor != null) {
+ SharedPreferencesCompat.EditorCompat.getInstance().apply(mEditor);
+ }
+ mNoCommit = noCommit;
+ }
+
+ /**
+ * Returns the context.
+ *
+ * @return The context.
+ */
+ Context getContext() {
+ return mContext;
+ }
+
+ public OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener() {
+ return mOnDisplayPreferenceDialogListener;
+ }
+
+ public void setOnDisplayPreferenceDialogListener(
+ OnDisplayPreferenceDialogListener onDisplayPreferenceDialogListener) {
+ mOnDisplayPreferenceDialogListener = onDisplayPreferenceDialogListener;
+ }
+
+ /**
+ * Called when a preference requests that a dialog be shown to complete a user interaction.
+ *
+ * @param preference The preference requesting the dialog.
+ */
+ public void showDialog(Preference preference) {
+ if (mOnDisplayPreferenceDialogListener != null) {
+ mOnDisplayPreferenceDialogListener.onDisplayPreferenceDialog(preference);
+ }
+ }
+
+ /**
+ * Sets the callback to be invoked when a {@link Preference} in the
+ * hierarchy rooted at this {@link PreferenceManager} is clicked.
+ *
+ * @param listener The callback to be invoked.
+ */
+ public void setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener) {
+ mOnPreferenceTreeClickListener = listener;
+ }
+
+ public OnPreferenceTreeClickListener getOnPreferenceTreeClickListener() {
+ return mOnPreferenceTreeClickListener;
+ }
+
+ /**
+ * Sets the callback to be invoked when a {@link PreferenceScreen} in the hierarchy rooted at
+ * this {@link PreferenceManager} is clicked.
+ *
+ * @param listener The callback to be invoked.
+ */
+ public void setOnNavigateToScreenListener(OnNavigateToScreenListener listener) {
+ mOnNavigateToScreenListener = listener;
+ }
+
+ /**
+ * Returns the {@link PreferenceManager.OnNavigateToScreenListener}, if one has been set.
+ */
+ public OnNavigateToScreenListener getOnNavigateToScreenListener() {
+ return mOnNavigateToScreenListener;
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a
+ * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
+ * clicked.
+ */
+ public interface OnPreferenceTreeClickListener {
+ /**
+ * Called when a preference in the tree rooted at this
+ * {@link PreferenceScreen} has been clicked.
+ *
+ * @param preference The preference that was clicked.
+ * @return Whether the click was handled.
+ */
+ boolean onPreferenceTreeClick(Preference preference);
+ }
+
+ /**
+ * Interface definition for a class that will be called when a
+ * {@link android.support.v7.preference.Preference} requests to display a dialog.
+ */
+ public interface OnDisplayPreferenceDialogListener {
+
+ /**
+ * Called when a preference in the tree requests to display a dialog.
+ *
+ * @param preference The Preference object requesting the dialog.
+ */
+ void onDisplayPreferenceDialog(Preference preference);
+ }
+
+ /**
+ * Interface definition for a class that will be called when a
+ * {@link android.support.v7.preference.PreferenceScreen} requests navigation.
+ */
+ public interface OnNavigateToScreenListener {
+
+ /**
+ * Called when a PreferenceScreen in the tree requests to navigate to its contents.
+ *
+ * @param preferenceScreen The PreferenceScreen requesting navigation.
+ */
+ void onNavigateToScreen(PreferenceScreen preferenceScreen);
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceScreen.java b/v7/preference/src/android/support/v7/preference/PreferenceScreen.java
new file mode 100644
index 0000000..2010080
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceScreen.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * Represents a top-level {@link Preference} that
+ * is the root of a Preference hierarchy. A {@link PreferenceFragmentCompat}
+ * points to an instance of this class to show the preferences. To instantiate
+ * this class, use {@link PreferenceManager#createPreferenceScreen(android.content.Context)}.
+ * <ul>
+ * This class can appear in two places:
+ * <li> When a {@link PreferenceFragmentCompat} points to this, it is used as the root
+ * and is not shown (only the contained preferences are shown).
+ * <li> When it appears inside another preference hierarchy, it is shown and
+ * serves as the gateway to another screen of preferences (either by showing
+ * another screen of preferences as a {@link android.app.Dialog} or via a
+ * {@link android.content.Context#startActivity(android.content.Intent)} from the
+ * {@link Preference#getIntent()}). The children of this {@link PreferenceScreen}
+ * are NOT shown in the screen that this {@link PreferenceScreen} is shown in.
+ * Instead, a separate screen will be shown when this preference is clicked.
+ * </ul>
+ * <p>Here's an example XML layout of a PreferenceScreen:</p>
+ * <pre>
+ <PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="first_preferencescreen">
+ <CheckBoxPreference
+ android:key="wifi enabled"
+ android:title="WiFi" />
+ <PreferenceScreen
+ android:key="second_preferencescreen"
+ android:title="WiFi settings">
+ <CheckBoxPreference
+ android:key="prefer wifi"
+ android:title="Prefer WiFi" />
+ ... other preferences here ...
+ </PreferenceScreen>
+ </PreferenceScreen> </pre>
+ * <p>
+ * In this example, the "first_preferencescreen" will be used as the root of the
+ * hierarchy and given to a {@link PreferenceFragment} or {@link PreferenceFragmentCompat}.
+ * The first screen will
+ * show preferences "WiFi" (which can be used to quickly enable/disable WiFi)
+ * and "WiFi settings". The "WiFi settings" is the "second_preferencescreen" and when
+ * clicked will show another screen of preferences such as "Prefer WiFi" (and
+ * the other preferences that are children of the "second_preferencescreen" tag).
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about building a settings UI with Preferences,
+ * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
+ * guide.</p>
+ * </div>
+ *
+ * @see PreferenceCategory
+ */
+public final class PreferenceScreen extends PreferenceGroup {
+
+ /**
+ * Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}.
+ * @hide-
+ */
+ public PreferenceScreen(Context context, AttributeSet attrs) {
+ super(context, attrs, R.attr.preferenceScreenStyle);
+ }
+
+ @Override
+ protected void onClick() {
+ if (getIntent() != null || getFragment() != null || getPreferenceCount() == 0) {
+ return;
+ }
+ final PreferenceManager.OnNavigateToScreenListener listener =
+ getPreferenceManager().getOnNavigateToScreenListener();
+ if (listener != null) {
+ listener.onNavigateToScreen(this);
+ }
+ }
+
+ @Override
+ protected boolean isOnSameScreenAsChildren() {
+ return false;
+ }
+
+}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
new file mode 100644
index 0000000..c7e247c
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.support.annotation.IdRes;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+import android.view.View;
+
+/**
+ * A {@link android.support.v7.widget.RecyclerView.ViewHolder} class which caches views associated
+ * with the default {@link Preference} layouts. Cached views can be retrieved by calling
+ * {@link #findViewById(int)}.
+ */
+public class PreferenceViewHolder extends RecyclerView.ViewHolder {
+ private final SparseArray<View> mCachedViews = new SparseArray<>(4);
+
+ /* package */ PreferenceViewHolder(View itemView) {
+ super(itemView);
+
+ // Pre-cache the views that we know in advance we'll want to find
+ mCachedViews.put(android.R.id.title, itemView.findViewById(android.R.id.title));
+ mCachedViews.put(android.R.id.summary, itemView.findViewById(android.R.id.summary));
+ mCachedViews.put(android.R.id.icon, itemView.findViewById(android.R.id.icon));
+ mCachedViews.put(R.id.icon_frame, itemView.findViewById(R.id.icon_frame));
+ }
+
+ /**
+ * Returns a cached reference to a subview managed by this object. If the view reference is not
+ * yet cached, it falls back to calling {@link View#findViewById(int)} and caches the result.
+ *
+ * @param id Resource ID of the view to find
+ * @return The view, or null if no view with the requested ID is found.
+ */
+ public View findViewById(@IdRes int id) {
+ final View cachedView = mCachedViews.get(id);
+ if (cachedView != null) {
+ return cachedView;
+ } else {
+ final View v = itemView.findViewById(id);
+ if (v != null) {
+ mCachedViews.put(id, v);
+ }
+ return v;
+ }
+ }
+}
diff --git a/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java b/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java
new file mode 100644
index 0000000..2e0e38b
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/SwitchPreferenceCompat.java
@@ -0,0 +1,212 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.widget.SwitchCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.CompoundButton;
+
+/**
+* A {@link Preference} that provides a two-state toggleable option.
+* <p>
+* This preference will store a boolean into the SharedPreferences.
+*
+* @attr ref android.R.styleable#SwitchPreference_summaryOff
+* @attr ref android.R.styleable#SwitchPreference_summaryOn
+* @attr ref android.R.styleable#SwitchPreference_switchTextOff
+* @attr ref android.R.styleable#SwitchPreference_switchTextOn
+* @attr ref android.R.styleable#SwitchPreference_disableDependentsState
+*/
+public class SwitchPreferenceCompat extends TwoStatePreference {
+ private final Listener mListener = new Listener();
+
+ // Switch text for on and off states
+ private CharSequence mSwitchOn;
+ private CharSequence mSwitchOff;
+
+ private class Listener implements CompoundButton.OnCheckedChangeListener {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (!callChangeListener(isChecked)) {
+ // Listener didn't like it, change it back.
+ // CompoundButton will make sure we don't recurse.
+ buttonView.setChecked(!isChecked);
+ return;
+ }
+
+ SwitchPreferenceCompat.this.setChecked(isChecked);
+ }
+ }
+
+ /**
+ * Construct a new SwitchPreference with the given style options.
+ *
+ * @param context The Context that will style this preference
+ * @param attrs Style attributes that differ from the default
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ * @param defStyleRes A resource identifier of a style resource that
+ * supplies default values for the view, used only if
+ * defStyleAttr is 0 or can not be found in the theme. Can be 0
+ * to not look for defaults.
+ */
+ public SwitchPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.SwitchPreferenceCompat, defStyleAttr, defStyleRes);
+
+ setSummaryOn(TypedArrayUtils.getString(a, R.styleable.SwitchPreferenceCompat_summaryOn,
+ R.styleable.SwitchPreferenceCompat_android_summaryOn));
+
+ setSummaryOff(TypedArrayUtils.getString(a, R.styleable.SwitchPreferenceCompat_summaryOff,
+ R.styleable.SwitchPreferenceCompat_android_summaryOff));
+
+ setSwitchTextOn(TypedArrayUtils.getString(a,
+ R.styleable.SwitchPreferenceCompat_switchTextOn,
+ R.styleable.SwitchPreferenceCompat_android_switchTextOn));
+
+ setSwitchTextOff(TypedArrayUtils.getString(a,
+ R.styleable.SwitchPreferenceCompat_switchTextOff,
+ R.styleable.SwitchPreferenceCompat_android_switchTextOff));
+
+ setDisableDependentsState(TypedArrayUtils.getBoolean(a,
+ R.styleable.SwitchPreferenceCompat_disableDependentsState,
+ R.styleable.SwitchPreferenceCompat_android_disableDependentsState, false));
+
+ a.recycle();
+ }
+
+ /**
+ * Construct a new SwitchPreference with the given style options.
+ *
+ * @param context The Context that will style this preference
+ * @param attrs Style attributes that differ from the default
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the view. Can be 0 to not look for defaults.
+ */
+ public SwitchPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ /**
+ * Construct a new SwitchPreference with the given style options.
+ *
+ * @param context The Context that will style this preference
+ * @param attrs Style attributes that differ from the default
+ */
+ public SwitchPreferenceCompat(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.switchPreferenceCompatStyle);
+ }
+
+ /**
+ * Construct a new SwitchPreference with default style options.
+ *
+ * @param context The Context that will style this preference
+ */
+ public SwitchPreferenceCompat(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View checkableView = holder.findViewById(R.id.switchWidget);
+ if (checkableView != null && checkableView instanceof Checkable) {
+ if (checkableView instanceof SwitchCompat) {
+ final SwitchCompat switchView = (SwitchCompat) checkableView;
+ switchView.setOnCheckedChangeListener(null);
+ }
+
+ ((Checkable) checkableView).setChecked(mChecked);
+
+ if (checkableView instanceof SwitchCompat) {
+ final SwitchCompat switchView = (SwitchCompat) checkableView;
+ switchView.setTextOn(mSwitchOn);
+ switchView.setTextOff(mSwitchOff);
+ switchView.setOnCheckedChangeListener(mListener);
+ }
+ }
+
+ syncSummaryView(holder);
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the on state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param onText Text to display in the on state
+ */
+ public void setSwitchTextOn(CharSequence onText) {
+ mSwitchOn = onText;
+ notifyChanged();
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the off state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param offText Text to display in the off state
+ */
+ public void setSwitchTextOff(CharSequence offText) {
+ mSwitchOff = offText;
+ notifyChanged();
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the on state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param resId The text as a string resource ID
+ */
+ public void setSwitchTextOn(int resId) {
+ setSwitchTextOn(getContext().getString(resId));
+ }
+
+ /**
+ * Set the text displayed on the switch widget in the off state.
+ * This should be a very short string; one word if possible.
+ *
+ * @param resId The text as a string resource ID
+ */
+ public void setSwitchTextOff(int resId) {
+ setSwitchTextOff(getContext().getString(resId));
+ }
+
+ /**
+ * @return The text that will be displayed on the switch widget in the on state
+ */
+ public CharSequence getSwitchTextOn() {
+ return mSwitchOn;
+ }
+
+ /**
+ * @return The text that will be displayed on the switch widget in the off state
+ */
+ public CharSequence getSwitchTextOff() {
+ return mSwitchOff;
+ }
+}
diff --git a/v7/preference/src/android/support/v7/preference/TwoStatePreference.java b/v7/preference/src/android/support/v7/preference/TwoStatePreference.java
new file mode 100644
index 0000000..e7748cc
--- /dev/null
+++ b/v7/preference/src/android/support/v7/preference/TwoStatePreference.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.v7.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Common base class for preferences that have two selectable states, persist a
+ * boolean value in SharedPreferences, and may have dependent preferences that are
+ * enabled/disabled based on the current state.
+ */
+public abstract class TwoStatePreference extends Preference {
+
+ private CharSequence mSummaryOn;
+ private CharSequence mSummaryOff;
+ protected boolean mChecked;
+ private boolean mCheckedSet;
+ private boolean mDisableDependentsState;
+
+ public TwoStatePreference(
+ Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public TwoStatePreference(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TwoStatePreference(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ protected void onClick() {
+ super.onClick();
+
+ final boolean newValue = !isChecked();
+ if (callChangeListener(newValue)) {
+ setChecked(newValue);
+ }
+ }
+
+ /**
+ * Sets the checked state and saves it to the {@link SharedPreferences}.
+ *
+ * @param checked The checked state.
+ */
+ public void setChecked(boolean checked) {
+ // Always persist/notify the first time; don't assume the field's default of false.
+ final boolean changed = mChecked != checked;
+ if (changed || !mCheckedSet) {
+ mChecked = checked;
+ mCheckedSet = true;
+ persistBoolean(checked);
+ if (changed) {
+ notifyDependencyChange(shouldDisableDependents());
+ notifyChanged();
+ }
+ }
+ }
+
+ /**
+ * Returns the checked state.
+ *
+ * @return The checked state.
+ */
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ @Override
+ public boolean shouldDisableDependents() {
+ boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked;
+ return shouldDisable || super.shouldDisableDependents();
+ }
+
+ /**
+ * Sets the summary to be shown when checked.
+ *
+ * @param summary The summary to be shown when checked.
+ */
+ public void setSummaryOn(CharSequence summary) {
+ mSummaryOn = summary;
+ if (isChecked()) {
+ notifyChanged();
+ }
+ }
+
+ /**
+ * @see #setSummaryOn(CharSequence)
+ * @param summaryResId The summary as a resource.
+ */
+ public void setSummaryOn(int summaryResId) {
+ setSummaryOn(getContext().getString(summaryResId));
+ }
+
+ /**
+ * Returns the summary to be shown when checked.
+ * @return The summary.
+ */
+ public CharSequence getSummaryOn() {
+ return mSummaryOn;
+ }
+
+ /**
+ * Sets the summary to be shown when unchecked.
+ *
+ * @param summary The summary to be shown when unchecked.
+ */
+ public void setSummaryOff(CharSequence summary) {
+ mSummaryOff = summary;
+ if (!isChecked()) {
+ notifyChanged();
+ }
+ }
+
+ /**
+ * @see #setSummaryOff(CharSequence)
+ * @param summaryResId The summary as a resource.
+ */
+ public void setSummaryOff(int summaryResId) {
+ setSummaryOff(getContext().getString(summaryResId));
+ }
+
+ /**
+ * Returns the summary to be shown when unchecked.
+ * @return The summary.
+ */
+ public CharSequence getSummaryOff() {
+ return mSummaryOff;
+ }
+
+ /**
+ * Returns whether dependents are disabled when this preference is on ({@code true})
+ * or when this preference is off ({@code false}).
+ *
+ * @return Whether dependents are disabled when this preference is on ({@code true})
+ * or when this preference is off ({@code false}).
+ */
+ public boolean getDisableDependentsState() {
+ return mDisableDependentsState;
+ }
+
+ /**
+ * Sets whether dependents are disabled when this preference is on ({@code true})
+ * or when this preference is off ({@code false}).
+ *
+ * @param disableDependentsState The preference state that should disable dependents.
+ */
+ public void setDisableDependentsState(boolean disableDependentsState) {
+ mDisableDependentsState = disableDependentsState;
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getBoolean(index, false);
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setChecked(restoreValue ? getPersistedBoolean(mChecked)
+ : (Boolean) defaultValue);
+ }
+
+ /**
+ * Sync a summary holder contained within holder's subhierarchy with the correct summary text.
+ * @param holder PreferenceViewHolder which holds a reference to the summary view
+ */
+ protected void syncSummaryView(PreferenceViewHolder holder) {
+ // Sync the summary holder
+ TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+ if (summaryView != null) {
+ boolean useDefaultSummary = true;
+ if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
+ summaryView.setText(mSummaryOn);
+ useDefaultSummary = false;
+ } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
+ summaryView.setText(mSummaryOff);
+ useDefaultSummary = false;
+ }
+
+ if (useDefaultSummary) {
+ final CharSequence summary = getSummary();
+ if (!TextUtils.isEmpty(summary)) {
+ summaryView.setText(summary);
+ useDefaultSummary = false;
+ }
+ }
+
+ int newVisibility = View.GONE;
+ if (!useDefaultSummary) {
+ // Someone has written to it
+ newVisibility = View.VISIBLE;
+ }
+ if (newVisibility != summaryView.getVisibility()) {
+ summaryView.setVisibility(newVisibility);
+ }
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ myState.checked = isChecked();
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setChecked(myState.checked);
+ }
+
+ static class SavedState extends BaseSavedState {
+ boolean checked;
+
+ public SavedState(Parcel source) {
+ super(source);
+ checked = source.readInt() == 1;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(checked ? 1 : 0);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index dcf6806..0754c44 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.CallSuper;
import android.support.annotation.Nullable;
import android.support.v4.os.TraceCompat;
import android.support.v4.util.ArrayMap;
@@ -5798,6 +5799,7 @@
*
* @param view The RecyclerView this LayoutManager is bound to
*/
+ @CallSuper
public void onAttachedToWindow(RecyclerView view) {
}
@@ -5821,6 +5823,7 @@
* @param recycler The recycler to use if you prefer to recycle your children instead of
* keeping them around.
*/
+ @CallSuper
public void onDetachedFromWindow(RecyclerView view, Recycler recycler) {
onDetachedFromWindow(view);
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
index 6d7154c..e09fceb 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -211,20 +211,6 @@
checkForMainThreadException();
}
- public void testGrowLookup() throws Throwable {
- setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
- waitFirstLayout();
- mLayoutManager.expectLayouts(1);
- mAdapter.mItems.clear();
- mAdapter.dispatchDataSetChanged();
- mLayoutManager.waitForLayout(2);
- checkForMainThreadException();
- mLayoutManager.expectLayouts(2);
- mAdapter.addAndNotify(0, 30);
- mLayoutManager.waitForLayout(2);
- checkForMainThreadException();
- }
-
public void testRTL() throws Throwable {
for (boolean changeRtlAfter : new boolean[]{false, true}) {
for (Config config : mBaseVariations) {
diff --git a/v8/renderscript/Android.mk b/v8/renderscript/Android.mk
index a7755aa..f6f4471 100644
--- a/v8/renderscript/Android.mk
+++ b/v8/renderscript/Android.mk
@@ -24,11 +24,20 @@
LOCAL_CFLAGS += -std=c++11
LOCAL_MODULE := android-support-v8-renderscript
-LOCAL_SDK_VERSION := 21
+LOCAL_SDK_VERSION := 22
LOCAL_SRC_FILES := $(call all-java-files-under, java/src)
include $(BUILD_STATIC_JAVA_LIBRARY)
+# API Check
+# ---------------------------------------------
+support_module := $(LOCAL_MODULE)
+support_module_api_dir := $(LOCAL_PATH)/api
+support_module_src_files := $(LOCAL_SRC_FILES)
+support_module_java_libraries := $(LOCAL_MODULE)
+support_module_java_packages := android.support.v8.renderscript
+include $(SUPPORT_API_CHECK)
+
# TODO: Build the tests as an APK here
include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/v8/renderscript/api/current.txt b/v8/renderscript/api/current.txt
new file mode 100644
index 0000000..8827d1b
--- /dev/null
+++ b/v8/renderscript/api/current.txt
@@ -0,0 +1,901 @@
+package android.support.v8.renderscript {
+
+ public class Allocation extends android.support.v8.renderscript.BaseObj {
+ method public void copy1DRangeFrom(int, int, java.lang.Object);
+ method public void copy1DRangeFrom(int, int, int[]);
+ method public void copy1DRangeFrom(int, int, short[]);
+ method public void copy1DRangeFrom(int, int, byte[]);
+ method public void copy1DRangeFrom(int, int, float[]);
+ method public void copy1DRangeFrom(int, int, android.support.v8.renderscript.Allocation, int);
+ method public void copy1DRangeFromUnchecked(int, int, java.lang.Object);
+ method public void copy1DRangeFromUnchecked(int, int, int[]);
+ method public void copy1DRangeFromUnchecked(int, int, short[]);
+ method public void copy1DRangeFromUnchecked(int, int, byte[]);
+ method public void copy1DRangeFromUnchecked(int, int, float[]);
+ method public void copy1DRangeTo(int, int, java.lang.Object);
+ method public void copy1DRangeTo(int, int, int[]);
+ method public void copy1DRangeTo(int, int, short[]);
+ method public void copy1DRangeTo(int, int, byte[]);
+ method public void copy1DRangeTo(int, int, float[]);
+ method public void copy1DRangeToUnchecked(int, int, java.lang.Object);
+ method public void copy1DRangeToUnchecked(int, int, int[]);
+ method public void copy1DRangeToUnchecked(int, int, short[]);
+ method public void copy1DRangeToUnchecked(int, int, byte[]);
+ method public void copy1DRangeToUnchecked(int, int, float[]);
+ method public void copy2DRangeFrom(int, int, int, int, java.lang.Object);
+ method public void copy2DRangeFrom(int, int, int, int, byte[]);
+ method public void copy2DRangeFrom(int, int, int, int, short[]);
+ method public void copy2DRangeFrom(int, int, int, int, int[]);
+ method public void copy2DRangeFrom(int, int, int, int, float[]);
+ method public void copy2DRangeFrom(int, int, int, int, android.support.v8.renderscript.Allocation, int, int);
+ method public void copy2DRangeFrom(int, int, android.graphics.Bitmap);
+ method public void copy2DRangeTo(int, int, int, int, java.lang.Object);
+ method public void copy2DRangeTo(int, int, int, int, byte[]);
+ method public void copy2DRangeTo(int, int, int, int, short[]);
+ method public void copy2DRangeTo(int, int, int, int, int[]);
+ method public void copy2DRangeTo(int, int, int, int, float[]);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, java.lang.Object);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, android.support.v8.renderscript.Allocation, int, int, int);
+ method public void copyFrom(android.support.v8.renderscript.BaseObj[]);
+ method public void copyFrom(java.lang.Object);
+ method public void copyFrom(int[]);
+ method public void copyFrom(short[]);
+ method public void copyFrom(byte[]);
+ method public void copyFrom(float[]);
+ method public void copyFrom(android.graphics.Bitmap);
+ method public void copyFrom(android.support.v8.renderscript.Allocation);
+ method public void copyFromUnchecked(java.lang.Object);
+ method public void copyFromUnchecked(int[]);
+ method public void copyFromUnchecked(short[]);
+ method public void copyFromUnchecked(byte[]);
+ method public void copyFromUnchecked(float[]);
+ method public void copyTo(android.graphics.Bitmap);
+ method public void copyTo(java.lang.Object);
+ method public void copyTo(byte[]);
+ method public void copyTo(short[]);
+ method public void copyTo(int[]);
+ method public void copyTo(float[]);
+ method public static android.support.v8.renderscript.Allocation createCubemapFromBitmap(android.support.v8.renderscript.RenderScript, android.graphics.Bitmap, android.support.v8.renderscript.Allocation.MipmapControl, int);
+ method public static android.support.v8.renderscript.Allocation createCubemapFromBitmap(android.support.v8.renderscript.RenderScript, android.graphics.Bitmap);
+ method public static android.support.v8.renderscript.Allocation createCubemapFromCubeFaces(android.support.v8.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.support.v8.renderscript.Allocation.MipmapControl, int);
+ method public static android.support.v8.renderscript.Allocation createCubemapFromCubeFaces(android.support.v8.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap);
+ method public static android.support.v8.renderscript.Allocation createFromBitmap(android.support.v8.renderscript.RenderScript, android.graphics.Bitmap, android.support.v8.renderscript.Allocation.MipmapControl, int);
+ method public static android.support.v8.renderscript.Allocation createFromBitmap(android.support.v8.renderscript.RenderScript, android.graphics.Bitmap);
+ method public static android.support.v8.renderscript.Allocation createFromBitmapResource(android.support.v8.renderscript.RenderScript, android.content.res.Resources, int, android.support.v8.renderscript.Allocation.MipmapControl, int);
+ method public static android.support.v8.renderscript.Allocation createFromBitmapResource(android.support.v8.renderscript.RenderScript, android.content.res.Resources, int);
+ method public static android.support.v8.renderscript.Allocation createFromString(android.support.v8.renderscript.RenderScript, java.lang.String, int);
+ method public static android.support.v8.renderscript.Allocation createSized(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element, int, int);
+ method public static android.support.v8.renderscript.Allocation createSized(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element, int);
+ method public static android.support.v8.renderscript.Allocation createTyped(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Type, android.support.v8.renderscript.Allocation.MipmapControl, int);
+ method public static android.support.v8.renderscript.Allocation createTyped(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Type, int);
+ method public static android.support.v8.renderscript.Allocation createTyped(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Type);
+ method public void generateMipmaps();
+ method public int getBytesSize();
+ method public android.support.v8.renderscript.Element getElement();
+ method public long getIncAllocID();
+ method public android.support.v8.renderscript.Type getType();
+ method public int getUsage();
+ method public void ioReceive();
+ method public void ioSend();
+ method public void ioSendOutput();
+ method public void setAutoPadding(boolean);
+ method public void setFromFieldPacker(int, android.support.v8.renderscript.FieldPacker);
+ method public void setFromFieldPacker(int, int, android.support.v8.renderscript.FieldPacker);
+ method public void setIncAllocID(long);
+ method public void setSurface(android.view.Surface);
+ method public void syncAll(int);
+ field public static final int USAGE_GRAPHICS_TEXTURE = 2; // 0x2
+ field public static final int USAGE_IO_INPUT = 32; // 0x20
+ field public static final int USAGE_IO_OUTPUT = 64; // 0x40
+ field public static final int USAGE_SCRIPT = 1; // 0x1
+ field public static final int USAGE_SHARED = 128; // 0x80
+ }
+
+ public static final class Allocation.MipmapControl extends java.lang.Enum {
+ method public static android.support.v8.renderscript.Allocation.MipmapControl valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.Allocation.MipmapControl[] values();
+ enum_constant public static final android.support.v8.renderscript.Allocation.MipmapControl MIPMAP_FULL;
+ enum_constant public static final android.support.v8.renderscript.Allocation.MipmapControl MIPMAP_NONE;
+ enum_constant public static final android.support.v8.renderscript.Allocation.MipmapControl MIPMAP_ON_SYNC_TO_TEXTURE;
+ }
+
+ public class BaseObj {
+ method public void destroy();
+ }
+
+ public class Byte2 {
+ ctor public Byte2();
+ ctor public Byte2(byte, byte);
+ field public byte x;
+ field public byte y;
+ }
+
+ public class Byte3 {
+ ctor public Byte3();
+ ctor public Byte3(byte, byte, byte);
+ field public byte x;
+ field public byte y;
+ field public byte z;
+ }
+
+ public class Byte4 {
+ ctor public Byte4();
+ ctor public Byte4(byte, byte, byte, byte);
+ field public byte w;
+ field public byte x;
+ field public byte y;
+ field public byte z;
+ }
+
+ public class Double2 {
+ ctor public Double2();
+ ctor public Double2(double, double);
+ field public double x;
+ field public double y;
+ }
+
+ public class Double3 {
+ ctor public Double3();
+ ctor public Double3(double, double, double);
+ field public double x;
+ field public double y;
+ field public double z;
+ }
+
+ public class Double4 {
+ ctor public Double4();
+ ctor public Double4(double, double, double, double);
+ field public double w;
+ field public double x;
+ field public double y;
+ field public double z;
+ }
+
+ public class Element extends android.support.v8.renderscript.BaseObj {
+ method public static android.support.v8.renderscript.Element ALLOCATION(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element A_8(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element BOOLEAN(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element ELEMENT(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F32(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F32_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F32_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F32_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F64(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F64_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F64_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element F64_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I16(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I16_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I16_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I16_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I32(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I32_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I32_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I32_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I64(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I64_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I64_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I64_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I8(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I8_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I8_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element I8_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element MATRIX_2X2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element MATRIX_3X3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element MATRIX_4X4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element RGBA_4444(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element RGBA_5551(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element RGBA_8888(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element RGB_565(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element RGB_888(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element SAMPLER(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element SCRIPT(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element TYPE(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U16(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U16_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U16_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U16_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U32(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U32_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U32_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U32_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U64(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U64_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U64_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U64_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U8(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U8_2(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U8_3(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element U8_4(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Element createPixel(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element.DataType, android.support.v8.renderscript.Element.DataKind);
+ method public static android.support.v8.renderscript.Element createVector(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element.DataType, int);
+ method public int getBytesSize();
+ method public android.support.v8.renderscript.Element.DataKind getDataKind();
+ method public android.support.v8.renderscript.Element.DataType getDataType();
+ method public long getDummyElement(android.support.v8.renderscript.RenderScript);
+ method public android.support.v8.renderscript.Element getSubElement(int);
+ method public int getSubElementArraySize(int);
+ method public int getSubElementCount();
+ method public java.lang.String getSubElementName(int);
+ method public int getSubElementOffsetBytes(int);
+ method public int getVectorSize();
+ method public boolean isCompatible(android.support.v8.renderscript.Element);
+ method public boolean isComplex();
+ }
+
+ public static class Element.Builder {
+ ctor public Element.Builder(android.support.v8.renderscript.RenderScript);
+ method public android.support.v8.renderscript.Element.Builder add(android.support.v8.renderscript.Element, java.lang.String, int);
+ method public android.support.v8.renderscript.Element.Builder add(android.support.v8.renderscript.Element, java.lang.String);
+ method public android.support.v8.renderscript.Element create();
+ }
+
+ public static final class Element.DataKind extends java.lang.Enum {
+ method public static android.support.v8.renderscript.Element.DataKind valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.Element.DataKind[] values();
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_A;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_DEPTH;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_L;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_LA;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_RGB;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_RGBA;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind PIXEL_YUV;
+ enum_constant public static final android.support.v8.renderscript.Element.DataKind USER;
+ }
+
+ public static final class Element.DataType extends java.lang.Enum {
+ method public static android.support.v8.renderscript.Element.DataType valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.Element.DataType[] values();
+ enum_constant public static final android.support.v8.renderscript.Element.DataType BOOLEAN;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType FLOAT_32;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType FLOAT_64;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType MATRIX_2X2;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType MATRIX_3X3;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType MATRIX_4X4;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType NONE;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType RS_ALLOCATION;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType RS_ELEMENT;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType RS_SAMPLER;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType RS_SCRIPT;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType RS_TYPE;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType SIGNED_16;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType SIGNED_32;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType SIGNED_64;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType SIGNED_8;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_16;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_32;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_4_4_4_4;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_5_5_5_1;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_5_6_5;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_64;
+ enum_constant public static final android.support.v8.renderscript.Element.DataType UNSIGNED_8;
+ }
+
+ public class FieldPacker {
+ ctor public FieldPacker(int);
+ ctor public FieldPacker(byte[]);
+ method public void addBoolean(boolean);
+ method public void addF32(float);
+ method public void addF32(android.support.v8.renderscript.Float2);
+ method public void addF32(android.support.v8.renderscript.Float3);
+ method public void addF32(android.support.v8.renderscript.Float4);
+ method public void addF64(double);
+ method public void addF64(android.support.v8.renderscript.Double2);
+ method public void addF64(android.support.v8.renderscript.Double3);
+ method public void addF64(android.support.v8.renderscript.Double4);
+ method public void addI16(short);
+ method public void addI16(android.support.v8.renderscript.Short2);
+ method public void addI16(android.support.v8.renderscript.Short3);
+ method public void addI16(android.support.v8.renderscript.Short4);
+ method public void addI32(int);
+ method public void addI32(android.support.v8.renderscript.Int2);
+ method public void addI32(android.support.v8.renderscript.Int3);
+ method public void addI32(android.support.v8.renderscript.Int4);
+ method public void addI64(long);
+ method public void addI64(android.support.v8.renderscript.Long2);
+ method public void addI64(android.support.v8.renderscript.Long3);
+ method public void addI64(android.support.v8.renderscript.Long4);
+ method public void addI8(byte);
+ method public void addI8(android.support.v8.renderscript.Byte2);
+ method public void addI8(android.support.v8.renderscript.Byte3);
+ method public void addI8(android.support.v8.renderscript.Byte4);
+ method public void addMatrix(android.support.v8.renderscript.Matrix4f);
+ method public void addMatrix(android.support.v8.renderscript.Matrix3f);
+ method public void addMatrix(android.support.v8.renderscript.Matrix2f);
+ method public void addObj(android.support.v8.renderscript.BaseObj);
+ method public void addU16(int);
+ method public void addU16(android.support.v8.renderscript.Int2);
+ method public void addU16(android.support.v8.renderscript.Int3);
+ method public void addU16(android.support.v8.renderscript.Int4);
+ method public void addU32(long);
+ method public void addU32(android.support.v8.renderscript.Long2);
+ method public void addU32(android.support.v8.renderscript.Long3);
+ method public void addU32(android.support.v8.renderscript.Long4);
+ method public void addU64(long);
+ method public void addU64(android.support.v8.renderscript.Long2);
+ method public void addU64(android.support.v8.renderscript.Long3);
+ method public void addU64(android.support.v8.renderscript.Long4);
+ method public void addU8(short);
+ method public void addU8(android.support.v8.renderscript.Short2);
+ method public void addU8(android.support.v8.renderscript.Short3);
+ method public void addU8(android.support.v8.renderscript.Short4);
+ method public void align(int);
+ method public final byte[] getData();
+ method public void reset();
+ method public void reset(int);
+ method public void skip(int);
+ method public boolean subBoolean();
+ method public android.support.v8.renderscript.Byte2 subByte2();
+ method public android.support.v8.renderscript.Byte3 subByte3();
+ method public android.support.v8.renderscript.Byte4 subByte4();
+ method public android.support.v8.renderscript.Double2 subDouble2();
+ method public android.support.v8.renderscript.Double3 subDouble3();
+ method public android.support.v8.renderscript.Double4 subDouble4();
+ method public float subF32();
+ method public double subF64();
+ method public android.support.v8.renderscript.Float2 subFloat2();
+ method public android.support.v8.renderscript.Float3 subFloat3();
+ method public android.support.v8.renderscript.Float4 subFloat4();
+ method public short subI16();
+ method public int subI32();
+ method public long subI64();
+ method public byte subI8();
+ method public android.support.v8.renderscript.Int2 subInt2();
+ method public android.support.v8.renderscript.Int3 subInt3();
+ method public android.support.v8.renderscript.Int4 subInt4();
+ method public android.support.v8.renderscript.Long2 subLong2();
+ method public android.support.v8.renderscript.Long3 subLong3();
+ method public android.support.v8.renderscript.Long4 subLong4();
+ method public android.support.v8.renderscript.Matrix2f subMatrix2f();
+ method public android.support.v8.renderscript.Matrix3f subMatrix3f();
+ method public android.support.v8.renderscript.Matrix4f subMatrix4f();
+ method public android.support.v8.renderscript.Short2 subShort2();
+ method public android.support.v8.renderscript.Short3 subShort3();
+ method public android.support.v8.renderscript.Short4 subShort4();
+ method public void subalign(int);
+ }
+
+ public class Float2 {
+ ctor public Float2();
+ ctor public Float2(float, float);
+ field public float x;
+ field public float y;
+ }
+
+ public class Float3 {
+ ctor public Float3();
+ ctor public Float3(float, float, float);
+ field public float x;
+ field public float y;
+ field public float z;
+ }
+
+ public class Float4 {
+ ctor public Float4();
+ ctor public Float4(float, float, float, float);
+ field public float w;
+ field public float x;
+ field public float y;
+ field public float z;
+ }
+
+ public class Int2 {
+ ctor public Int2();
+ ctor public Int2(int, int);
+ field public int x;
+ field public int y;
+ }
+
+ public class Int3 {
+ ctor public Int3();
+ ctor public Int3(int, int, int);
+ field public int x;
+ field public int y;
+ field public int z;
+ }
+
+ public class Int4 {
+ ctor public Int4();
+ ctor public Int4(int, int, int, int);
+ field public int w;
+ field public int x;
+ field public int y;
+ field public int z;
+ }
+
+ public class Long2 {
+ ctor public Long2();
+ ctor public Long2(long, long);
+ field public long x;
+ field public long y;
+ }
+
+ public class Long3 {
+ ctor public Long3();
+ ctor public Long3(long, long, long);
+ field public long x;
+ field public long y;
+ field public long z;
+ }
+
+ public class Long4 {
+ ctor public Long4();
+ ctor public Long4(long, long, long, long);
+ field public long w;
+ field public long x;
+ field public long y;
+ field public long z;
+ }
+
+ public class Matrix2f {
+ ctor public Matrix2f();
+ ctor public Matrix2f(float[]);
+ method public float get(int, int);
+ method public float[] getArray();
+ method public void load(android.support.v8.renderscript.Matrix2f);
+ method public void loadIdentity();
+ method public void loadMultiply(android.support.v8.renderscript.Matrix2f, android.support.v8.renderscript.Matrix2f);
+ method public void loadRotate(float);
+ method public void loadScale(float, float);
+ method public void multiply(android.support.v8.renderscript.Matrix2f);
+ method public void rotate(float);
+ method public void scale(float, float);
+ method public void set(int, int, float);
+ method public void transpose();
+ }
+
+ public class Matrix3f {
+ ctor public Matrix3f();
+ ctor public Matrix3f(float[]);
+ method public float get(int, int);
+ method public float[] getArray();
+ method public void load(android.support.v8.renderscript.Matrix3f);
+ method public void loadIdentity();
+ method public void loadMultiply(android.support.v8.renderscript.Matrix3f, android.support.v8.renderscript.Matrix3f);
+ method public void loadRotate(float, float, float, float);
+ method public void loadRotate(float);
+ method public void loadScale(float, float);
+ method public void loadScale(float, float, float);
+ method public void loadTranslate(float, float);
+ method public void multiply(android.support.v8.renderscript.Matrix3f);
+ method public void rotate(float, float, float, float);
+ method public void rotate(float);
+ method public void scale(float, float);
+ method public void scale(float, float, float);
+ method public void set(int, int, float);
+ method public void translate(float, float);
+ method public void transpose();
+ }
+
+ public class Matrix4f {
+ ctor public Matrix4f();
+ ctor public Matrix4f(float[]);
+ method public float get(int, int);
+ method public float[] getArray();
+ method public boolean inverse();
+ method public boolean inverseTranspose();
+ method public void load(android.support.v8.renderscript.Matrix4f);
+ method public void loadFrustum(float, float, float, float, float, float);
+ method public void loadIdentity();
+ method public void loadMultiply(android.support.v8.renderscript.Matrix4f, android.support.v8.renderscript.Matrix4f);
+ method public void loadOrtho(float, float, float, float, float, float);
+ method public void loadOrthoWindow(int, int);
+ method public void loadPerspective(float, float, float, float);
+ method public void loadProjectionNormalized(int, int);
+ method public void loadRotate(float, float, float, float);
+ method public void loadScale(float, float, float);
+ method public void loadTranslate(float, float, float);
+ method public void multiply(android.support.v8.renderscript.Matrix4f);
+ method public void rotate(float, float, float, float);
+ method public void scale(float, float, float);
+ method public void set(int, int, float);
+ method public void translate(float, float, float);
+ method public void transpose();
+ }
+
+ public class RSDriverException extends android.support.v8.renderscript.RSRuntimeException {
+ ctor public RSDriverException(java.lang.String);
+ }
+
+ public class RSIllegalArgumentException extends android.support.v8.renderscript.RSRuntimeException {
+ ctor public RSIllegalArgumentException(java.lang.String);
+ }
+
+ public class RSInvalidStateException extends android.support.v8.renderscript.RSRuntimeException {
+ ctor public RSInvalidStateException(java.lang.String);
+ }
+
+ public class RSRuntimeException extends java.lang.RuntimeException {
+ ctor public RSRuntimeException(java.lang.String);
+ }
+
+ public class RenderScript {
+ method public void contextDump();
+ method public static android.support.v8.renderscript.RenderScript create(android.content.Context);
+ method public static android.support.v8.renderscript.RenderScript create(android.content.Context, android.support.v8.renderscript.RenderScript.ContextType);
+ method public static android.support.v8.renderscript.RenderScript create(android.content.Context, android.support.v8.renderscript.RenderScript.ContextType, int);
+ method public static android.support.v8.renderscript.RenderScript create(android.content.Context, int, android.support.v8.renderscript.RenderScript.ContextType, int);
+ method public static android.support.v8.renderscript.RenderScript createMultiContext(android.content.Context, android.support.v8.renderscript.RenderScript.ContextType, int, int);
+ method public void destroy();
+ method public void finish();
+ method public static void forceCompat();
+ method public final android.content.Context getApplicationContext();
+ method public android.support.v8.renderscript.RenderScript.RSErrorHandler getErrorHandler();
+ method public android.support.v8.renderscript.RenderScript.RSMessageHandler getMessageHandler();
+ method public static void releaseAllContexts();
+ method public void sendMessage(int, int[]);
+ method public static void setBlackList(java.lang.String);
+ method public void setErrorHandler(android.support.v8.renderscript.RenderScript.RSErrorHandler);
+ method public void setMessageHandler(android.support.v8.renderscript.RenderScript.RSMessageHandler);
+ method public void setPriority(android.support.v8.renderscript.RenderScript.Priority);
+ field public static final int CREATE_FLAG_NONE = 0; // 0x0
+ }
+
+ public static final class RenderScript.ContextType extends java.lang.Enum {
+ method public static android.support.v8.renderscript.RenderScript.ContextType valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.RenderScript.ContextType[] values();
+ enum_constant public static final android.support.v8.renderscript.RenderScript.ContextType DEBUG;
+ enum_constant public static final android.support.v8.renderscript.RenderScript.ContextType NORMAL;
+ enum_constant public static final android.support.v8.renderscript.RenderScript.ContextType PROFILE;
+ }
+
+ public static final class RenderScript.Priority extends java.lang.Enum {
+ method public static android.support.v8.renderscript.RenderScript.Priority valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.RenderScript.Priority[] values();
+ enum_constant public static final android.support.v8.renderscript.RenderScript.Priority LOW;
+ enum_constant public static final android.support.v8.renderscript.RenderScript.Priority NORMAL;
+ }
+
+ public static class RenderScript.RSErrorHandler implements java.lang.Runnable {
+ ctor public RenderScript.RSErrorHandler();
+ method public void run();
+ field protected java.lang.String mErrorMessage;
+ field protected int mErrorNum;
+ }
+
+ public static class RenderScript.RSMessageHandler implements java.lang.Runnable {
+ ctor public RenderScript.RSMessageHandler();
+ method public void run();
+ field protected int[] mData;
+ field protected int mID;
+ field protected int mLength;
+ }
+
+ public class Sampler extends android.support.v8.renderscript.BaseObj {
+ method public static android.support.v8.renderscript.Sampler CLAMP_LINEAR(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler CLAMP_LINEAR_MIP_LINEAR(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler CLAMP_NEAREST(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler MIRRORED_REPEAT_LINEAR(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler MIRRORED_REPEAT_NEAREST(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler WRAP_LINEAR(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler WRAP_LINEAR_MIP_LINEAR(android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.Sampler WRAP_NEAREST(android.support.v8.renderscript.RenderScript);
+ method public float getAnisotropy();
+ method public android.support.v8.renderscript.Sampler.Value getMagnification();
+ method public android.support.v8.renderscript.Sampler.Value getMinification();
+ method public android.support.v8.renderscript.Sampler.Value getWrapS();
+ method public android.support.v8.renderscript.Sampler.Value getWrapT();
+ }
+
+ public static class Sampler.Builder {
+ ctor public Sampler.Builder(android.support.v8.renderscript.RenderScript);
+ method public android.support.v8.renderscript.Sampler create();
+ method public void setAnisotropy(float);
+ method public void setMagnification(android.support.v8.renderscript.Sampler.Value);
+ method public void setMinification(android.support.v8.renderscript.Sampler.Value);
+ method public void setWrapS(android.support.v8.renderscript.Sampler.Value);
+ method public void setWrapT(android.support.v8.renderscript.Sampler.Value);
+ }
+
+ public static final class Sampler.Value extends java.lang.Enum {
+ method public static android.support.v8.renderscript.Sampler.Value valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.Sampler.Value[] values();
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value CLAMP;
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value LINEAR;
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value LINEAR_MIP_LINEAR;
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value LINEAR_MIP_NEAREST;
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value MIRRORED_REPEAT;
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value NEAREST;
+ enum_constant public static final android.support.v8.renderscript.Sampler.Value WRAP;
+ }
+
+ public class Script extends android.support.v8.renderscript.BaseObj {
+ method public void bindAllocation(android.support.v8.renderscript.Allocation, int);
+ method protected android.support.v8.renderscript.Script.FieldID createFieldID(int, android.support.v8.renderscript.Element);
+ method protected android.support.v8.renderscript.Script.InvokeID createInvokeID(int);
+ method protected android.support.v8.renderscript.Script.KernelID createKernelID(int, int, android.support.v8.renderscript.Element, android.support.v8.renderscript.Element);
+ method protected void forEach(int, android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation, android.support.v8.renderscript.FieldPacker);
+ method protected void forEach(int, android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation, android.support.v8.renderscript.FieldPacker, android.support.v8.renderscript.Script.LaunchOptions);
+ method protected void invoke(int);
+ method protected void invoke(int, android.support.v8.renderscript.FieldPacker);
+ method protected boolean isIncSupp();
+ method protected void setIncSupp(boolean);
+ method public void setTimeZone(java.lang.String);
+ method public void setVar(int, float);
+ method public void setVar(int, double);
+ method public void setVar(int, int);
+ method public void setVar(int, long);
+ method public void setVar(int, boolean);
+ method public void setVar(int, android.support.v8.renderscript.BaseObj);
+ method public void setVar(int, android.support.v8.renderscript.FieldPacker);
+ method public void setVar(int, android.support.v8.renderscript.FieldPacker, android.support.v8.renderscript.Element, int[]);
+ }
+
+ public static class Script.Builder {
+ }
+
+ public static class Script.FieldBase {
+ ctor protected Script.FieldBase();
+ method public android.support.v8.renderscript.Allocation getAllocation();
+ method public android.support.v8.renderscript.Element getElement();
+ method public android.support.v8.renderscript.Type getType();
+ method protected void init(android.support.v8.renderscript.RenderScript, int);
+ method protected void init(android.support.v8.renderscript.RenderScript, int, int);
+ method public void updateAllocation();
+ field protected android.support.v8.renderscript.Allocation mAllocation;
+ field protected android.support.v8.renderscript.Element mElement;
+ }
+
+ public static final class Script.FieldID extends android.support.v8.renderscript.BaseObj {
+ }
+
+ public static final class Script.InvokeID extends android.support.v8.renderscript.BaseObj {
+ }
+
+ public static final class Script.KernelID extends android.support.v8.renderscript.BaseObj {
+ }
+
+ public static final class Script.LaunchOptions {
+ ctor public Script.LaunchOptions();
+ method public int getXEnd();
+ method public int getXStart();
+ method public int getYEnd();
+ method public int getYStart();
+ method public int getZEnd();
+ method public int getZStart();
+ method public android.support.v8.renderscript.Script.LaunchOptions setX(int, int);
+ method public android.support.v8.renderscript.Script.LaunchOptions setY(int, int);
+ method public android.support.v8.renderscript.Script.LaunchOptions setZ(int, int);
+ }
+
+ public class ScriptC extends android.support.v8.renderscript.Script {
+ ctor protected ScriptC(long, android.support.v8.renderscript.RenderScript);
+ ctor protected ScriptC(android.support.v8.renderscript.RenderScript, android.content.res.Resources, int);
+ ctor protected ScriptC(android.support.v8.renderscript.RenderScript, java.lang.String, byte[], byte[]);
+ }
+
+ public final class ScriptGroup extends android.support.v8.renderscript.BaseObj {
+ method public java.lang.Object[] execute(java.lang.Object...);
+ method public deprecated void execute();
+ method public deprecated void setInput(android.support.v8.renderscript.Script.KernelID, android.support.v8.renderscript.Allocation);
+ method public deprecated void setOutput(android.support.v8.renderscript.Script.KernelID, android.support.v8.renderscript.Allocation);
+ }
+
+ public static final class ScriptGroup.Binding {
+ ctor public ScriptGroup.Binding(android.support.v8.renderscript.Script.FieldID, java.lang.Object);
+ method public android.support.v8.renderscript.Script.FieldID getField();
+ method public java.lang.Object getValue();
+ }
+
+ public static final deprecated class ScriptGroup.Builder {
+ ctor public ScriptGroup.Builder(android.support.v8.renderscript.RenderScript);
+ method public android.support.v8.renderscript.ScriptGroup.Builder addConnection(android.support.v8.renderscript.Type, android.support.v8.renderscript.Script.KernelID, android.support.v8.renderscript.Script.FieldID);
+ method public android.support.v8.renderscript.ScriptGroup.Builder addConnection(android.support.v8.renderscript.Type, android.support.v8.renderscript.Script.KernelID, android.support.v8.renderscript.Script.KernelID);
+ method public android.support.v8.renderscript.ScriptGroup.Builder addKernel(android.support.v8.renderscript.Script.KernelID);
+ method public android.support.v8.renderscript.ScriptGroup create();
+ }
+
+ public static final class ScriptGroup.Builder2 {
+ ctor public ScriptGroup.Builder2(android.support.v8.renderscript.RenderScript);
+ method public android.support.v8.renderscript.ScriptGroup.Input addInput();
+ method public android.support.v8.renderscript.ScriptGroup.Closure addInvoke(android.support.v8.renderscript.Script.InvokeID, java.lang.Object...);
+ method public android.support.v8.renderscript.ScriptGroup.Closure addKernel(android.support.v8.renderscript.Script.KernelID, android.support.v8.renderscript.Type, java.lang.Object...);
+ method public android.support.v8.renderscript.ScriptGroup create(java.lang.String, android.support.v8.renderscript.ScriptGroup.Future...);
+ }
+
+ public static final class ScriptGroup.Closure extends android.support.v8.renderscript.BaseObj {
+ method public android.support.v8.renderscript.ScriptGroup.Future getGlobal(android.support.v8.renderscript.Script.FieldID);
+ method public android.support.v8.renderscript.ScriptGroup.Future getReturn();
+ }
+
+ public static final class ScriptGroup.Future {
+ }
+
+ public static final class ScriptGroup.Input {
+ }
+
+ public abstract class ScriptIntrinsic extends android.support.v8.renderscript.Script {
+ }
+
+ public class ScriptIntrinsic3DLUT extends android.support.v8.renderscript.ScriptIntrinsic {
+ ctor protected ScriptIntrinsic3DLUT(long, android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public static android.support.v8.renderscript.ScriptIntrinsic3DLUT create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setLUT(android.support.v8.renderscript.Allocation);
+ }
+
+ public class ScriptIntrinsicBlend extends android.support.v8.renderscript.ScriptIntrinsic {
+ method public static android.support.v8.renderscript.ScriptIntrinsicBlend create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEachAdd(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachClear(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachDst(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachDstAtop(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachDstIn(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachDstOut(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachDstOver(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachMultiply(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachSrc(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachSrcAtop(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachSrcIn(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachSrcOut(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachSrcOver(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachSubtract(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEachXor(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDAdd();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDClear();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDDst();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDDstAtop();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDDstIn();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDDstOut();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDDstOver();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDMultiply();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDSrc();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDSrcAtop();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDSrcIn();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDSrcOut();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDSrcOver();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDSubtract();
+ method public android.support.v8.renderscript.Script.KernelID getKernelIDXor();
+ }
+
+ public class ScriptIntrinsicBlur extends android.support.v8.renderscript.ScriptIntrinsic {
+ ctor protected ScriptIntrinsicBlur(long, android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.ScriptIntrinsicBlur create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation);
+ method public android.support.v8.renderscript.Script.FieldID getFieldID_Input();
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setInput(android.support.v8.renderscript.Allocation);
+ method public void setRadius(float);
+ }
+
+ public class ScriptIntrinsicColorMatrix extends android.support.v8.renderscript.ScriptIntrinsic {
+ ctor protected ScriptIntrinsicColorMatrix(long, android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.ScriptIntrinsicColorMatrix create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Script.LaunchOptions);
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setAdd(android.support.v8.renderscript.Float4);
+ method public void setAdd(float, float, float, float);
+ method public void setColorMatrix(android.support.v8.renderscript.Matrix4f);
+ method public void setColorMatrix(android.support.v8.renderscript.Matrix3f);
+ method public void setGreyscale();
+ method public void setRGBtoYUV();
+ method public void setYUVtoRGB();
+ }
+
+ public class ScriptIntrinsicConvolve3x3 extends android.support.v8.renderscript.ScriptIntrinsic {
+ method public static android.support.v8.renderscript.ScriptIntrinsicConvolve3x3 create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Script.LaunchOptions);
+ method public android.support.v8.renderscript.Script.FieldID getFieldID_Input();
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setCoefficients(float[]);
+ method public void setInput(android.support.v8.renderscript.Allocation);
+ }
+
+ public class ScriptIntrinsicConvolve5x5 extends android.support.v8.renderscript.ScriptIntrinsic {
+ method public static android.support.v8.renderscript.ScriptIntrinsicConvolve5x5 create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Script.LaunchOptions);
+ method public android.support.v8.renderscript.Script.FieldID getFieldID_Input();
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setCoefficients(float[]);
+ method public void setInput(android.support.v8.renderscript.Allocation);
+ }
+
+ public class ScriptIntrinsicHistogram extends android.support.v8.renderscript.ScriptIntrinsic {
+ ctor protected ScriptIntrinsicHistogram(long, android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.ScriptIntrinsicHistogram create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Script.LaunchOptions);
+ method public void forEach_Dot(android.support.v8.renderscript.Allocation);
+ method public void forEach_Dot(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Script.LaunchOptions);
+ method public android.support.v8.renderscript.Script.FieldID getFieldID_Input();
+ method public android.support.v8.renderscript.Script.KernelID getKernelID_Separate();
+ method public void setDotCoefficients(float, float, float, float);
+ method public void setOutput(android.support.v8.renderscript.Allocation);
+ }
+
+ public class ScriptIntrinsicLUT extends android.support.v8.renderscript.ScriptIntrinsic {
+ ctor protected ScriptIntrinsicLUT(long, android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.ScriptIntrinsicLUT create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Allocation);
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setAlpha(int, int);
+ method public void setBlue(int, int);
+ method public void setGreen(int, int);
+ method public void setRed(int, int);
+ }
+
+ public class ScriptIntrinsicResize extends android.support.v8.renderscript.ScriptIntrinsic {
+ ctor protected ScriptIntrinsicResize(long, android.support.v8.renderscript.RenderScript);
+ method public static android.support.v8.renderscript.ScriptIntrinsicResize create(android.support.v8.renderscript.RenderScript);
+ method public void forEach_bicubic(android.support.v8.renderscript.Allocation);
+ method public void forEach_bicubic(android.support.v8.renderscript.Allocation, android.support.v8.renderscript.Script.LaunchOptions);
+ method public android.support.v8.renderscript.Script.FieldID getFieldID_Input();
+ method public android.support.v8.renderscript.Script.KernelID getKernelID_bicubic();
+ method public void setInput(android.support.v8.renderscript.Allocation);
+ }
+
+ public class ScriptIntrinsicYuvToRGB extends android.support.v8.renderscript.ScriptIntrinsic {
+ method public static android.support.v8.renderscript.ScriptIntrinsicYuvToRGB create(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public void forEach(android.support.v8.renderscript.Allocation);
+ method public android.support.v8.renderscript.Script.FieldID getFieldID_Input();
+ method public android.support.v8.renderscript.Script.KernelID getKernelID();
+ method public void setInput(android.support.v8.renderscript.Allocation);
+ }
+
+ public class Short2 {
+ ctor public Short2();
+ ctor public Short2(short, short);
+ field public short x;
+ field public short y;
+ }
+
+ public class Short3 {
+ ctor public Short3();
+ ctor public Short3(short, short, short);
+ field public short x;
+ field public short y;
+ field public short z;
+ }
+
+ public class Short4 {
+ ctor public Short4();
+ ctor public Short4(short, short, short, short);
+ field public short w;
+ field public short x;
+ field public short y;
+ field public short z;
+ }
+
+ public class Type extends android.support.v8.renderscript.BaseObj {
+ method public static android.support.v8.renderscript.Type createX(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element, int);
+ method public static android.support.v8.renderscript.Type createXY(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element, int, int);
+ method public static android.support.v8.renderscript.Type createXYZ(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element, int, int, int);
+ method public int getCount();
+ method public long getDummyType(android.support.v8.renderscript.RenderScript, long);
+ method public android.support.v8.renderscript.Element getElement();
+ method public int getX();
+ method public int getY();
+ method public int getYuv();
+ method public int getZ();
+ method public boolean hasFaces();
+ method public boolean hasMipmaps();
+ }
+
+ public static class Type.Builder {
+ ctor public Type.Builder(android.support.v8.renderscript.RenderScript, android.support.v8.renderscript.Element);
+ method public android.support.v8.renderscript.Type create();
+ method public android.support.v8.renderscript.Type.Builder setFaces(boolean);
+ method public android.support.v8.renderscript.Type.Builder setMipmaps(boolean);
+ method public android.support.v8.renderscript.Type.Builder setX(int);
+ method public android.support.v8.renderscript.Type.Builder setY(int);
+ method public android.support.v8.renderscript.Type.Builder setYuvFormat(int);
+ method public android.support.v8.renderscript.Type.Builder setZ(int);
+ }
+
+ public static final class Type.CubemapFace extends java.lang.Enum {
+ method public static android.support.v8.renderscript.Type.CubemapFace valueOf(java.lang.String);
+ method public static final android.support.v8.renderscript.Type.CubemapFace[] values();
+ enum_constant public static final android.support.v8.renderscript.Type.CubemapFace NEGATIVE_X;
+ enum_constant public static final android.support.v8.renderscript.Type.CubemapFace NEGATIVE_Y;
+ enum_constant public static final android.support.v8.renderscript.Type.CubemapFace NEGATIVE_Z;
+ enum_constant public static final android.support.v8.renderscript.Type.CubemapFace POSITIVE_X;
+ enum_constant public static final android.support.v8.renderscript.Type.CubemapFace POSITIVE_Y;
+ enum_constant public static final android.support.v8.renderscript.Type.CubemapFace POSITIVE_Z;
+ }
+
+}
+
diff --git a/v8/renderscript/api/removed.txt b/v8/renderscript/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/v8/renderscript/api/removed.txt
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java b/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
index 92c3eb5..03244ff 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
@@ -265,7 +265,6 @@
}
/**
- * @hide
* Enable/Disable AutoPadding for Vec3 elements.
*
* @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
@@ -463,7 +462,6 @@
/**
* Delete once code is updated.
- * @hide
*/
public void ioSendOutput() {
ioSend();
@@ -1214,10 +1212,7 @@
}
}
- /**
- * @hide
- *
- */
+
private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
Object array, Element.DataType dt, int arrayLen) {
mRS.validate();
@@ -1243,7 +1238,6 @@
}
/**
- * @hide
* Copy a rectangular region from the array into the allocation.
* The array is assumed to be tightly packed.
*
@@ -1262,7 +1256,6 @@
}
/**
- * @hide
* Copy a rectangular region into the allocation from another
* allocation.
*
@@ -1437,7 +1430,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1452,7 +1444,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1465,7 +1456,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1478,7 +1468,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1491,7 +1480,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1505,7 +1493,6 @@
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type does not
* match the component type of the array passed in.
@@ -1521,7 +1508,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 32 bit
* integer type.
@@ -1536,7 +1522,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 16 bit
* integer type.
@@ -1551,7 +1536,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not an 8 bit
* integer type.
@@ -1566,7 +1550,6 @@
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 32 bit float
* type.
@@ -1605,7 +1588,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1621,7 +1603,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1637,7 +1618,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1653,7 +1633,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1669,7 +1648,6 @@
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
index 7922b9e..5570ca2 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
@@ -58,6 +58,30 @@
private Context mApplicationContext;
private String mNativeLibDir;
+ static private String mBlackList = "";
+ /**
+ * Sets the blackList of Models to only use support lib runtime.
+ * Should be used before context create.
+ *
+ * @param blackList User provided black list string.
+ *
+ * Format: "(MANUFACTURER1:PRODUCT1:MODEL1), (MANUFACTURER2:PRODUCT2:MODEL2)..."
+ * e.g. : To Blacklist Nexus 7(2013) and Nexus 5.
+ * mBlackList = "(asus:razor:Nexus 7), (LGE:hammerhead:Nexus 5)";
+ */
+ static public void setBlackList(String blackList) {
+ if (blackList != null) {
+ mBlackList = blackList;
+ }
+ }
+ /**
+ * Force using support lib runtime.
+ * Should be used before context create.
+ *
+ */
+ static public void forceCompat() {
+ sNative = 0;
+ }
/*
* We use a class initializer to allow the native code to cache some
* field offsets.
@@ -140,46 +164,67 @@
if (sNative == 1) {
// Workarounds that may disable thunking go here
- ApplicationInfo info;
+ ApplicationInfo info = null;
try {
info = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(),
PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
// assume no workarounds needed
- return true;
- }
- long minorVersion = 0;
-
- // load minorID from reflection
- try {
- Class<?> javaRS = Class.forName("android.renderscript.RenderScript");
- Method getMinorID = javaRS.getDeclaredMethod("getMinorID");
- minorVersion = ((java.lang.Long)getMinorID.invoke(null)).longValue();
- } catch (Exception e) {
- // minor version remains 0 on devices with no possible WARs
}
- if (info.metaData != null) {
- // asynchronous teardown: minor version 1+
- if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableAsyncTeardown") == true) {
- if (minorVersion == 0) {
- sNative = 0;
+ if (info != null) {
+ long minorVersion = 0;
+ // load minorID from reflection
+ try {
+ Class<?> javaRS = Class.forName("android.renderscript.RenderScript");
+ if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
+ Method getMinorID = javaRS.getDeclaredMethod("getMinorID");
+ minorVersion = ((java.lang.Long)getMinorID.invoke(null)).longValue();
+ } else {
+ //For M+
+ Method getMinorVersion = javaRS.getDeclaredMethod("getMinorVersion");
+ minorVersion = ((java.lang.Long)getMinorVersion.invoke(null)).longValue();
}
+ } catch (Exception e) {
+ // minor version remains 0 on devices with no possible WARs
}
- // blur issues on some drivers with 4.4
- if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableBlurWorkaround") == true) {
- if (android.os.Build.VERSION.SDK_INT <= 19) {
- //android.util.Log.e("rs", "war on");
- sNative = 0;
+ if (info.metaData != null) {
+ // asynchronous teardown: minor version 1+
+ if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableAsyncTeardown") == true) {
+ if (minorVersion == 0) {
+ sNative = 0;
+ }
+ }
+
+ // blur issues on some drivers with 4.4
+ if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableBlurWorkaround") == true) {
+ if (android.os.Build.VERSION.SDK_INT <= 19) {
+ //android.util.Log.e("rs", "war on");
+ sNative = 0;
+ }
}
}
+ // end of workarounds
}
- // end of workarounds
}
}
if (sNative == 1) {
+ // check against the blacklist
+ if (mBlackList.length() > 0) {
+ String deviceInfo = '(' +
+ android.os.Build.MANUFACTURER +
+ ':' +
+ android.os.Build.PRODUCT +
+ ':' +
+ android.os.Build.MODEL +
+ ')';
+ if (mBlackList.contains(deviceInfo)) {
+ sNative = 0;
+ return false;
+ }
+ }
return true;
}
return false;
@@ -698,7 +743,7 @@
Log.e(LOG_TAG, "Error loading RS Compat library for Incremental Intrinsic Support: " + e);
throw new RSRuntimeException("Error loading RS Compat library for Incremental Intrinsic Support: " + e);
}
- if (!nIncLoadSO()) {
+ if (!nIncLoadSO(sSdkVersion)) {
throw new RSRuntimeException("Error loading libRSSupport library for Incremental Intrinsic Support");
}
mIncLoaded = true;
@@ -782,8 +827,12 @@
long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
long[] depFieldIDs) {
validate();
- return rsnClosureCreate(mContext, kernelID, returnValue, fieldIDs, values,
+ long c = rsnClosureCreate(mContext, kernelID, returnValue, fieldIDs, values,
sizes, depClosures, depFieldIDs);
+ if (c == 0) {
+ throw new RSRuntimeException("Failed creating closure.");
+ }
+ return c;
}
native long rsnInvokeClosureCreate(long con, long invokeID, byte[] params,
@@ -791,8 +840,12 @@
synchronized long nInvokeClosureCreate(long invokeID, byte[] params,
long[] fieldIDs, long[] values, int[] sizes) {
validate();
- return rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
+ long c = rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
values, sizes);
+ if (c == 0) {
+ throw new RSRuntimeException("Failed creating closure.");
+ }
+ return c;
}
native void rsnClosureSetArg(long con, long closureID, int index,
@@ -829,7 +882,7 @@
// Additional Entry points For inc libRSSupport
- native boolean nIncLoadSO();
+ native boolean nIncLoadSO(int deviceApi);
native long nIncDeviceCreate();
native void nIncDeviceDestroy(long dev);
// Methods below are wrapped to protect the non-threadsafe
@@ -1018,8 +1071,6 @@
* Place a message into the message queue to be sent back to the message
* handler once all previous commands have been executed.
*
- * @hide
- *
* @param id
* @param data
*/
@@ -1244,7 +1295,7 @@
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
useIOlib = true;
}
- if (!rs.nLoadSO(useNative, android.os.Build.VERSION.SDK_INT)) {
+ if (!rs.nLoadSO(useNative, sdkVersion)) {
if (useNative) {
android.util.Log.v(LOG_TAG, "Unable to load libRS.so, falling back to compat mode");
useNative = false;
@@ -1255,7 +1306,7 @@
Log.e(LOG_TAG, "Error loading RS Compat library: " + e);
throw new RSRuntimeException("Error loading RS Compat library: " + e);
}
- if (!rs.nLoadSO(false, android.os.Build.VERSION.SDK_INT)) {
+ if (!rs.nLoadSO(false, sdkVersion)) {
throw new RSRuntimeException("Error loading libRSSupport library");
}
}
@@ -1364,7 +1415,6 @@
/**
* Gets or creates a RenderScript context of the specified type.
*
- * @hide
* @param ctx The context.
* @param ct The type of context to be created.
* @param sdkVersion The target SDK Version.
@@ -1390,7 +1440,6 @@
}
/**
- * @hide
*
* Releases all the process contexts. This is the same as
* calling .destroy() on each unique context retreived with
@@ -1428,7 +1477,6 @@
*
* If you need a single context please use create()
*
- * @hide
* @param ctx The context.
* @return RenderScript
*/
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Script.java b/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
index 41e7e08..7cef892 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
@@ -109,7 +109,6 @@
* This class should not be directly created. Instead use the method in the
* reflected or intrinsic code "getInvokeID_funcname()".
*
- * @hide
*/
public static final class InvokeID extends BaseObj {
Script mScript;
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
index 6861754..15e8b55 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
@@ -41,10 +41,10 @@
* runtime and compiler optimization can be applied to reduce computation and
* communication overhead, and to make better use of the CPU and the GPU.
**/
-public class ScriptGroup extends BaseObj {
+public final class ScriptGroup extends BaseObj {
//FIXME: Change 23 to the codename when that is decided.
private static final int MIN_API_VERSION = 23;
-
+ private static final String TAG = "ScriptGroup";
IO mOutputs[];
IO mInputs[];
private boolean mUseIncSupp = false;
@@ -100,8 +100,8 @@
* <p>
* A closure represents a function call to a kernel or invocable function,
* combined with arguments and values for global variables. A closure is
- * created using the {@link android.renderscript.ScriptGroup.Builder2#addKernel} or
- * {@link android.renderscript.ScriptGroup.Builder2#addInvoke}
+ * created using the {@link Builder2#addKernel} or
+ * {@link Builder2#addInvoke}
* method.
*/
@@ -117,11 +117,11 @@
private static final String TAG = "Closure";
- private Closure(long id, RenderScript rs) {
+ Closure(long id, RenderScript rs) {
super(id, rs);
}
- private Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
+ Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
Object[] args, Map<Script.FieldID, Object> globals) {
super(0, rs);
@@ -144,28 +144,16 @@
int i;
for (i = 0; i < args.length; i++) {
- Object obj = args[i];
fieldIDs[i] = 0;
- if (obj instanceof Input) {
- Input unbound = (Input)obj;
- unbound.addReference(this, i);
- } else {
- retrieveValueAndDependenceInfo(rs, i, args[i], values, sizes,
- depClosures, depFieldIDs);
- }
+ retrieveValueAndDependenceInfo(rs, i, null, args[i],
+ values, sizes, depClosures, depFieldIDs);
}
-
for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
Object obj = entry.getValue();
Script.FieldID fieldID = entry.getKey();
fieldIDs[i] = fieldID.getID(rs);
- if (obj instanceof Input) {
- Input unbound = (Input)obj;
- unbound.addReference(this, fieldID);
- } else {
- retrieveValueAndDependenceInfo(rs, i, obj, values,
- sizes, depClosures, depFieldIDs);
- }
+ retrieveValueAndDependenceInfo(rs, i, fieldID, obj,
+ values, sizes, depClosures, depFieldIDs);
i++;
}
@@ -175,8 +163,8 @@
setID(id);
}
- private Closure(RenderScript rs, Script.InvokeID invokeID,
- Object[] args, Map<Script.FieldID, Object> globals) {
+ Closure(RenderScript rs, Script.InvokeID invokeID,
+ Object[] args, Map<Script.FieldID, Object> globals) {
super(0, rs);
if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
@@ -202,14 +190,8 @@
Object obj = entry.getValue();
Script.FieldID fieldID = entry.getKey();
fieldIDs[i] = fieldID.getID(rs);
- if (obj instanceof Input) {
- Input unbound = (Input)obj;
- unbound.addReference(this, fieldID);
- } else {
- // TODO(yangni): Verify obj not a future.
- retrieveValueAndDependenceInfo(rs, i, obj, values,
- sizes, depClosures, depFieldIDs);
- }
+ retrieveValueAndDependenceInfo(rs, i, fieldID, obj, values,
+ sizes, depClosures, depFieldIDs);
i++;
}
@@ -219,9 +201,8 @@
setID(id);
}
- private static
- void retrieveValueAndDependenceInfo(RenderScript rs,
- int index, Object obj,
+ private void retrieveValueAndDependenceInfo(RenderScript rs,
+ int index, Script.FieldID fid, Object obj,
long[] values, int[] sizes,
long[] depClosures,
long[] depFieldIDs) {
@@ -232,20 +213,25 @@
depClosures[index] = f.getClosure().getID(rs);
Script.FieldID fieldID = f.getFieldID();
depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
- if (obj == null) {
- // Value is originally created by the owner closure
- values[index] = 0;
- sizes[index] = 0;
- return;
- }
} else {
depClosures[index] = 0;
depFieldIDs[index] = 0;
}
- ValueAndSize vs = new ValueAndSize(rs, obj);
- values[index] = vs.value;
- sizes[index] = vs.size;
+ if (obj instanceof Input) {
+ Input unbound = (Input)obj;
+ if (index < mArgs.length) {
+ unbound.addReference(this, index);
+ } else {
+ unbound.addReference(this, fid);
+ }
+ values[index] = 0;
+ sizes[index] = 0;
+ } else {
+ ValueAndSize vs = new ValueAndSize(rs, obj);
+ values[index] = vs.value;
+ sizes[index] = vs.size;
+ }
}
/**
@@ -277,7 +263,11 @@
// without an associated value (reference). So this is not working for
// cross-module (cross-script) linking in this case where a field not
// explicitly bound.
- f = new Future(this, field, mBindings.get(field));
+ Object obj = mBindings.get(field);
+ if (obj instanceof Future) {
+ obj = ((Future)obj).getValue();
+ }
+ f = new Future(this, field, obj);
mGlobalFuture.put(field, f);
}
@@ -285,12 +275,18 @@
}
void setArg(int index, Object obj) {
+ if (obj instanceof Future) {
+ obj = ((Future)obj).getValue();
+ }
mArgs[index] = obj;
ValueAndSize vs = new ValueAndSize(mRS, obj);
mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
}
void setGlobal(Script.FieldID fieldID, Object obj) {
+ if (obj instanceof Future) {
+ obj = ((Future)obj).getValue();
+ }
mBindings.put(fieldID, obj);
ValueAndSize vs = new ValueAndSize(mRS, obj);
mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
@@ -363,6 +359,7 @@
// -1 means unset. Legal values are 0 .. n-1, where n is the number of
// arguments for the referencing closure.
List<Pair<Closure, Integer>> mArgIndex;
+ Object mValue;
Input() {
mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>();
@@ -378,6 +375,7 @@
}
void set(Object value) {
+ mValue = value;
for (Pair<Closure, Integer> p : mArgIndex) {
Closure closure = p.first;
int index = p.second.intValue();
@@ -389,14 +387,14 @@
closure.setGlobal(fieldID, value);
}
}
+
+ Object get() { return mValue; }
}
- String mName;
- List<Closure> mClosures;
- List<Input> mInputs2;
- Future[] mOutputs2;
-
- private static final String TAG = "ScriptGroup2";
+ private String mName;
+ private List<Closure> mClosures;
+ private List<Input> mInputs2;
+ private Future[] mOutputs2;
ScriptGroup(long id, RenderScript rs) {
super(id, rs);
@@ -458,26 +456,16 @@
Object[] outputObjs = new Object[mOutputs2.length];
int i = 0;
for (Future f : mOutputs2) {
- outputObjs[i++] = f.getValue();
+ Object output = f.getValue();
+ if (output instanceof Input) {
+ output = ((Input)output).get();
+ }
+ outputObjs[i++] = output;
}
return outputObjs;
}
/**
- * Represents a binding of a value to a global variable in a
- * kernel or invocable function. Used in closure creation.
- */
-
- public static final class Binding {
- public Script.FieldID mField;
- public Object mValue;
- public Binding(Script.FieldID field, Object value) {
- mField = field;
- mValue = value;
- }
- }
-
- /**
* Sets an input of the ScriptGroup. This specifies an
* Allocation to be used for kernels that require an input
* Allocation provided from outside of the ScriptGroup.
@@ -695,7 +683,8 @@
Node n = mNodes.get(ct);
if (n.mInputs.size() == 0) {
if (n.mOutputs.size() == 0 && mNodes.size() > 1) {
- throw new RSInvalidStateException("Groups cannot contain unconnected scripts");
+ String msg = "Groups cannot contain unconnected scripts";
+ throw new RSInvalidStateException(msg);
}
validateDAGRecurse(n, ct+1);
}
@@ -976,6 +965,40 @@
}
/**
+ * Represents a binding of a value to a global variable in a
+ * kernel or invocable function. Used in closure creation.
+ */
+
+ public static final class Binding {
+ private final Script.FieldID mField;
+ private final Object mValue;
+
+ /**
+ * Returns a Binding object that binds value to field
+ *
+ * @param field the Script.FieldID of the global variable
+ * @param value the value
+ */
+
+ public Binding(Script.FieldID field, Object value) {
+ mField = field;
+ mValue = value;
+ }
+
+ /**
+ * Returns the field ID
+ */
+
+ public Script.FieldID getField() { return mField; }
+
+ /**
+ * Returns the value
+ */
+
+ public Object getValue() { return mValue; }
+ }
+
+ /**
* The builder class for creating script groups
* <p>
* A script group is created using closures (see class {@link Closure}).
@@ -1013,21 +1036,45 @@
RenderScript mRS;
List<Closure> mClosures;
List<Input> mInputs;
- private static final String TAG = "ScriptGroup2.Builder";
+ private static final String TAG = "ScriptGroup.Builder2";
+ /**
+ * Returns a Builder object
+ *
+ * @param rs the RenderScript context
+ */
public Builder2(RenderScript rs) {
mRS = rs;
mClosures = new ArrayList<Closure>();
mInputs = new ArrayList<Input>();
}
+ /**
+ * Adds a closure for a kernel
+ *
+ * @param k Kernel ID for the kernel function
+ * @param returnType Allocation type for the return value
+ * @param args arguments to the kernel function
+ * @param globalBindings bindings for global variables
+ * @return a closure
+ */
+
private Closure addKernelInternal(Script.KernelID k, Type returnType, Object[] args,
- Map<Script.FieldID, Object> globalBindings) {
+ Map<Script.FieldID, Object> globalBindings) {
Closure c = new Closure(mRS, k, returnType, args, globalBindings);
mClosures.add(c);
return c;
}
+ /**
+ * Adds a closure for an invocable function
+ *
+ * @param invoke Invoke ID for the invocable function
+ * @param args arguments to the invocable function
+ * @param globalBindings bindings for global variables
+ * @return a closure
+ */
+
private Closure addInvokeInternal(Script.InvokeID invoke, Object[] args,
Map<Script.FieldID, Object> globalBindings) {
Closure c = new Closure(mRS, invoke, args, globalBindings);
@@ -1116,7 +1163,7 @@
return false;
}
Binding b = (Binding)argsAndBindings[i];
- bindingMap.put(b.mField, b.mValue);
+ bindingMap.put(b.getField(), b.getValue());
}
return true;
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
index dcd1bc1..7fc71f3 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
@@ -25,7 +25,6 @@
* allocation. The 8 nearest values are sampled and linearly interpolated. The
* result is placed in the output.
*
- * @hide
**/
public class ScriptIntrinsic3DLUT extends ScriptIntrinsic {
private Allocation mLUT;
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Type.java b/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
index 2fd894b..6aeb9ea 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
@@ -114,8 +114,6 @@
/**
* Get the YUV format
*
- * @hide
- *
* @return int
*/
public int getYuv() {
@@ -344,8 +342,6 @@
/**
* Set the YUV layout for a Type.
*
- * @hide
- *
* @param yuvFormat {@link android.graphics.ImageFormat#YV12} or {@link android.graphics.ImageFormat#NV21}
*/
public Builder setYuvFormat(int yuvFormat) {
diff --git a/v8/renderscript/jni/android_renderscript_RenderScript.cpp b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
index cddb309..525c6bd 100644
--- a/v8/renderscript/jni/android_renderscript_RenderScript.cpp
+++ b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
@@ -269,7 +269,7 @@
// Incremental Support lib
static dispatchTable dispatchTabInc;
-static jboolean nLoadSO(JNIEnv *_env, jobject _this, jboolean useNative, jint deviceApi) {
+static jboolean nLoadSO(JNIEnv *_env, jobject _this, jboolean useNative, jint targetApi) {
void* handle = NULL;
if (useNative) {
handle = dlopen("libRS.so", RTLD_LAZY | RTLD_LOCAL);
@@ -281,7 +281,7 @@
return false;
}
- if (loadSymbols(handle, dispatchTab, deviceApi) == false) {
+ if (loadSymbols(handle, dispatchTab, targetApi) == false) {
LOG_API("%s init failed!", filename);
return false;
}
@@ -345,79 +345,167 @@
jlong returnValue, jlongArray fieldIDArray,
jlongArray valueArray, jintArray sizeArray,
jlongArray depClosureArray, jlongArray depFieldIDArray) {
+ jlong ret = 0;
+
jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
- RsScriptFieldID* fieldIDs =
- (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * fieldIDs_length);
- for (int i = 0; i< fieldIDs_length; i++) {
- fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
- }
-
jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
jsize values_length = _env->GetArrayLength(valueArray);
- uintptr_t* values = (uintptr_t*)alloca(sizeof(uintptr_t) * values_length);
- for (int i = 0; i < values_length; i++) {
- values[i] = (uintptr_t)jValues[i];
- }
-
- jint* sizes = _env->GetIntArrayElements(sizeArray, nullptr);
+ jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
jsize sizes_length = _env->GetArrayLength(sizeArray);
-
jlong* jDepClosures =
_env->GetLongArrayElements(depClosureArray, nullptr);
jsize depClosures_length = _env->GetArrayLength(depClosureArray);
- RsClosure* depClosures =
- (RsClosure*)alloca(sizeof(RsClosure) * depClosures_length);
- for (int i = 0; i < depClosures_length; i++) {
- depClosures[i] = (RsClosure)jDepClosures[i];
- }
-
jlong* jDepFieldIDs =
_env->GetLongArrayElements(depFieldIDArray, nullptr);
jsize depFieldIDs_length = _env->GetArrayLength(depFieldIDArray);
- RsScriptFieldID* depFieldIDs =
- (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * depFieldIDs_length);
- for (int i = 0; i < depClosures_length; i++) {
+
+ size_t numValues, numDependencies;
+ RsScriptFieldID* fieldIDs;
+ uintptr_t* values;
+ RsClosure* depClosures;
+ RsScriptFieldID* depFieldIDs;
+
+ if (fieldIDs_length != values_length || values_length != sizes_length) {
+ LOG_API("Unmatched field IDs, values, and sizes in closure creation.");
+ goto exit;
+ }
+
+ numValues = (size_t)fieldIDs_length;
+
+ if (depClosures_length != depFieldIDs_length) {
+ LOG_API("Unmatched closures and field IDs for dependencies in closure creation.");
+ goto exit;
+ }
+
+ numDependencies = (size_t)depClosures_length;
+
+ if (numDependencies > numValues) {
+ LOG_API("Unexpected number of dependencies in closure creation");
+ goto exit;
+ }
+
+ if (numValues > RS_CLOSURE_MAX_NUMBER_ARGS_AND_BINDINGS) {
+ LOG_API("Too many arguments or globals in closure creation");
+ goto exit;
+ }
+
+ fieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numValues);
+ if (fieldIDs == nullptr) {
+ goto exit;
+ }
+
+ for (size_t i = 0; i < numValues; i++) {
+ fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
+ }
+
+ values = (uintptr_t*)alloca(sizeof(uintptr_t) * numValues);
+ if (values == nullptr) {
+ goto exit;
+ }
+
+ for (size_t i = 0; i < numValues; i++) {
+ values[i] = (uintptr_t)jValues[i];
+ }
+
+ depClosures = (RsClosure*)alloca(sizeof(RsClosure) * numDependencies);
+ if (depClosures == nullptr) {
+ goto exit;
+ }
+
+ for (size_t i = 0; i < numDependencies; i++) {
+ depClosures[i] = (RsClosure)jDepClosures[i];
+ }
+
+ depFieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numDependencies);
+ if (depFieldIDs == nullptr) {
+ goto exit;
+ }
+
+ for (size_t i = 0; i < numDependencies; i++) {
depFieldIDs[i] = (RsClosure)jDepFieldIDs[i];
}
- return (jlong)(uintptr_t)dispatchTab.ClosureCreate(
+ ret = (jlong)(uintptr_t)dispatchTab.ClosureCreate(
(RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
- fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
- (int*)sizes, (size_t)sizes_length,
- depClosures, (size_t)depClosures_length,
- depFieldIDs, (size_t)depFieldIDs_length);
+ fieldIDs, numValues, values, numValues,
+ (int*)jSizes, numValues,
+ depClosures, numDependencies,
+ depFieldIDs, numDependencies);
+
+exit:
+
+ _env->ReleaseLongArrayElements(depFieldIDArray, jDepFieldIDs, JNI_ABORT);
+ _env->ReleaseLongArrayElements(depClosureArray, jDepClosures, JNI_ABORT);
+ _env->ReleaseIntArrayElements (sizeArray, jSizes, JNI_ABORT);
+ _env->ReleaseLongArrayElements(valueArray, jValues, JNI_ABORT);
+ _env->ReleaseLongArrayElements(fieldIDArray, jFieldIDs, JNI_ABORT);
+
+ return ret;
}
static jlong
nInvokeClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong invokeID,
jbyteArray paramArray, jlongArray fieldIDArray, jlongArray valueArray,
jintArray sizeArray) {
+ jlong ret = 0;
+
jbyte* jParams = _env->GetByteArrayElements(paramArray, nullptr);
jsize jParamLength = _env->GetArrayLength(paramArray);
-
jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
- RsScriptFieldID* fieldIDs =
- (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * fieldIDs_length);
- for (int i = 0; i< fieldIDs_length; i++) {
+ jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
+ jsize values_length = _env->GetArrayLength(valueArray);
+ jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
+ jsize sizes_length = _env->GetArrayLength(sizeArray);
+
+ size_t numValues;
+ RsScriptFieldID* fieldIDs;
+ uintptr_t* values;
+
+ if (fieldIDs_length != values_length || values_length != sizes_length) {
+ LOG_API("Unmatched field IDs, values, and sizes in closure creation.");
+ goto exit;
+ }
+
+ numValues = (size_t) fieldIDs_length;
+
+ if (numValues > RS_CLOSURE_MAX_NUMBER_ARGS_AND_BINDINGS) {
+ LOG_API("Too many arguments or globals in closure creation");
+ goto exit;
+ }
+
+ fieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numValues);
+ if (fieldIDs == nullptr) {
+ goto exit;
+ }
+
+ for (size_t i = 0; i < numValues; i++) {
fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
}
- jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
- jsize values_length = _env->GetArrayLength(valueArray);
- uintptr_t* values = (uintptr_t*)alloca(sizeof(uintptr_t) * values_length);
- for (int i = 0; i < values_length; i++) {
+ values = (uintptr_t*)alloca(sizeof(uintptr_t) * numValues);
+ if (values == nullptr) {
+ goto exit;
+ }
+
+ for (size_t i = 0; i < numValues; i++) {
values[i] = (uintptr_t)jValues[i];
}
- jint* sizes = _env->GetIntArrayElements(sizeArray, nullptr);
- jsize sizes_length = _env->GetArrayLength(sizeArray);
-
- return (jlong)(uintptr_t)dispatchTab.InvokeClosureCreate(
+ ret = (jlong)(uintptr_t)dispatchTab.InvokeClosureCreate(
(RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
- fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
- (int*)sizes, (size_t)sizes_length);
+ fieldIDs, numValues, values, numValues,
+ (int*)jSizes, numValues);
+
+exit:
+
+ _env->ReleaseIntArrayElements (sizeArray, jSizes, JNI_ABORT);
+ _env->ReleaseLongArrayElements(valueArray, jValues, JNI_ABORT);
+ _env->ReleaseLongArrayElements(fieldIDArray, jFieldIDs, JNI_ABORT);
+ _env->ReleaseByteArrayElements(paramArray, jParams, JNI_ABORT);
+
+ return ret;
}
static void
@@ -437,20 +525,40 @@
static long
nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, jstring name,
jstring cacheDir, jlongArray closureArray) {
+ jlong ret = 0;
+
AutoJavaStringToUTF8 nameUTF(_env, name);
AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
jsize numClosures = _env->GetArrayLength(closureArray);
- RsClosure* closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures);
+
+ RsClosure* closures;
+
+ if (numClosures > (jsize) RS_SCRIPT_GROUP_MAX_NUMBER_CLOSURES) {
+ LOG_API("Too many closures in script group");
+ goto exit;
+ }
+
+ closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures);
+ if (closures == nullptr) {
+ goto exit;
+ }
+
for (int i = 0; i < numClosures; i++) {
closures[i] = (RsClosure)jClosures[i];
}
- return (jlong)(uintptr_t)dispatchTab.ScriptGroup2Create(
+ ret = (jlong)(uintptr_t)dispatchTab.ScriptGroup2Create(
(RsContext)con, nameUTF.c_str(), nameUTF.length(),
cacheDirUTF.c_str(), cacheDirUTF.length(),
closures, numClosures);
+
+exit:
+
+ _env->ReleaseLongArrayElements(closureArray, jClosures, JNI_ABORT);
+
+ return ret;
}
static void
@@ -1138,7 +1246,7 @@
(void *)script, slot, val);
if (mUseInc) {
dispatchTabInc.ScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
- } else {
+ } else {
dispatchTab.ScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
}
}
@@ -1389,7 +1497,7 @@
(void *)sid, slot, sig);
if (mUseInc) {
return (jlong)(uintptr_t)dispatchTabInc.ScriptKernelIDCreate((RsContext)con, (RsScript)sid,
- slot, sig);
+ slot, sig);
} else {
return (jlong)(uintptr_t)dispatchTab.ScriptKernelIDCreate((RsContext)con, (RsScript)sid,
slot, sig);
@@ -1524,7 +1632,7 @@
// ---------------------------------------------------------------------------
// For Incremental Intrinsic Support
-static bool nIncLoadSO() {
+static bool nIncLoadSO(jint deviceApi) {
void* handle = NULL;
handle = dlopen("libRSSupport.so", RTLD_LAZY | RTLD_LOCAL);
if (handle == NULL) {
@@ -1532,7 +1640,7 @@
return false;
}
- if (loadSymbols(handle, dispatchTabInc) == false) {
+ if (loadSymbols(handle, dispatchTabInc, deviceApi) == false) {
LOG_API("%s init failed!", filename);
return false;
}
@@ -1730,7 +1838,7 @@
{"rsnSystemGetPointerSize", "()I", (void*)nSystemGetPointerSize },
// Entry points for Inc libRSSupport
-{"nIncLoadSO", "()Z", (bool*)nIncLoadSO },
+{"nIncLoadSO", "(I)Z", (bool*)nIncLoadSO },
{"nIncDeviceCreate", "()J", (void*)nIncDeviceCreate },
{"nIncDeviceDestroy", "(J)V", (void*)nIncDeviceDestroy },
{"rsnIncContextCreate", "(JIII)J", (void*)nIncContextCreate },