Merge "Give transitioning fragment a context prior to retrieving transition" into mnc-ub-dev
diff --git a/build.gradle b/build.gradle
index 3b23406..8e89705 100644
--- a/build.gradle
+++ b/build.gradle
@@ -34,7 +34,7 @@
}
ext.supportRepoOut = new File(buildDir, 'support_repo')
-ext.testApkDistOut = new File(buildDir, 'test_apks')
+ext.testApkDistOut = ext.distDir
// Main task called by the build server.
task(createArchive) << {
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index 06d8d6f..cfd3895 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -18,25 +18,21 @@
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-vectordrawable
LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under, static util)
+LOCAL_SRC_FILES := $(call all-java-files-under, static common)
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 := current
-LOCAL_SRC_FILES := $(call all-java-files-under, animated util)
+LOCAL_SRC_FILES := $(call all-java-files-under, animated common)
LOCAL_JAVA_LIBRARIES := android-support-v4
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
-
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable
LOCAL_AAPT_FLAGS := --no-version-vectors
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
index 2b83d73..37f4a6f 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -25,7 +25,6 @@
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
@@ -126,7 +125,7 @@
* @attr ref android.R.styleable#AnimatedVectorDrawableCompatTarget_animation
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class AnimatedVectorDrawableCompat extends Drawable implements Animatable {
+public class AnimatedVectorDrawableCompat extends VectorDrawableCommon implements Animatable {
private static final String LOGTAG = "AnimatedVDCompat";
private static final String ANIMATED_VECTOR = "animated-vector";
@@ -138,9 +137,6 @@
private Context mContext;
- // Drawable delegation for Lollipop and above.
- AnimatedVectorDrawable mDelegateDrawable;
-
AnimatedVectorDrawableDelegateState mCachedConstantStateDelegate;
private AnimatedVectorDrawableCompat() {
@@ -461,82 +457,6 @@
return false;
}
- // Extra override functions for delegation for SDK >= 7.
- @Override
- public void clearColorFilter() {
- if (mDelegateDrawable != null) {
- mDelegateDrawable.clearColorFilter();
- return;
- }
- super.clearColorFilter();
- }
-
- @Override
- public Drawable getCurrent() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getCurrent();
- }
- return super.getCurrent();
- }
-
- @Override
- public int getMinimumWidth() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getMinimumWidth();
- }
- return super.getMinimumWidth();
- }
-
- @Override
- public int getMinimumHeight() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getMinimumHeight();
- }
- return super.getMinimumHeight();
- }
-
- @Override
- public boolean getPadding(Rect padding) {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getPadding(padding);
- }
- return super.getPadding(padding);
- }
-
- @Override
- public int[] getState() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getState();
- }
- return super.getState();
- }
-
-
- @Override
- public Region getTransparentRegion() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getTransparentRegion();
- }
- return super.getTransparentRegion();
- }
-
- @Override
- public void setChangingConfigurations(int configs) {
- if (mDelegateDrawable != null) {
- mDelegateDrawable.setChangingConfigurations(configs);
- return;
- }
- super.setChangingConfigurations(configs);
- }
-
- @Override
- public boolean setState(int[] stateSet) {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.setState(stateSet);
- }
- return super.setState(stateSet);
- }
-
/**
* Constant state for delegating the creating drawable job.
* Instead of creating a VectorDrawable, create a VectorDrawableCompat instance which contains
@@ -662,7 +582,7 @@
@Override
public boolean isRunning() {
if (mDelegateDrawable != null) {
- return mDelegateDrawable.isRunning();
+ return ((AnimatedVectorDrawable) mDelegateDrawable).isRunning();
}
final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
final int size = animators.size();
@@ -693,7 +613,7 @@
@Override
public void start() {
if (mDelegateDrawable != null) {
- mDelegateDrawable.start();
+ ((AnimatedVectorDrawable) mDelegateDrawable).start();
return;
}
// If any one of the animator has not ended, do nothing.
@@ -713,7 +633,7 @@
@Override
public void stop() {
if (mDelegateDrawable != null) {
- mDelegateDrawable.stop();
+ ((AnimatedVectorDrawable) mDelegateDrawable).stop();
return;
}
final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java b/graphics/drawable/common/src/android/support/graphics/drawable/AndroidResources.java
similarity index 100%
rename from graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
rename to graphics/drawable/common/src/android/support/graphics/drawable/AndroidResources.java
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java b/graphics/drawable/common/src/android/support/graphics/drawable/TypedArrayUtils.java
similarity index 100%
rename from graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
rename to graphics/drawable/common/src/android/support/graphics/drawable/TypedArrayUtils.java
diff --git a/graphics/drawable/common/src/android/support/graphics/drawable/VectorDrawableCommon.java b/graphics/drawable/common/src/android/support/graphics/drawable/VectorDrawableCommon.java
new file mode 100644
index 0000000..216932a
--- /dev/null
+++ b/graphics/drawable/common/src/android/support/graphics/drawable/VectorDrawableCommon.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.graphics.drawable;
+
+import android.annotation.TargetApi;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.ColorFilter;
+import android.graphics.Outline;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Internal common delegation shared by VectorDrawableCompat and AnimatedVectorDrawableCompat
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+abstract class VectorDrawableCommon extends Drawable {
+ /**
+ * Obtains styled attributes from the theme, if available, or unstyled
+ * resources if the theme is null.
+ */
+ static TypedArray obtainAttributes(
+ Resources res, Resources.Theme theme, AttributeSet set, int[] attrs) {
+ if (theme == null) {
+ return res.obtainAttributes(set, attrs);
+ }
+ return theme.obtainStyledAttributes(set, attrs, 0, 0);
+ }
+
+ // Drawable delegation for Lollipop and above.
+ Drawable mDelegateDrawable;
+
+ @Override
+ public void setColorFilter(int color, PorterDuff.Mode mode) {
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setColorFilter(color, mode);
+ return;
+ }
+ super.setColorFilter(color, mode);
+ }
+
+ @Override
+ public ColorFilter getColorFilter() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getColorFilter();
+ }
+ return super.getColorFilter();
+ }
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.setLevel(level);
+ }
+ return super.onLevelChange(level);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setBounds(bounds);
+ return;
+ }
+ super.onBoundsChange(bounds);
+ }
+
+ @Override
+ public void setHotspot(float x, float y) {
+ // API >= 21 only.
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setHotspot(x, y);
+ }
+ return;
+ }
+
+ @Override
+ public void setHotspotBounds(int left, int top, int right, int bottom) {
+ // API >= 21 only.
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setHotspotBounds(left, top, right, bottom);
+ return;
+ }
+ }
+
+ @TargetApi(23)
+ @Override
+ public void getHotspotBounds(Rect outRect) {
+ // API >= 21 only.
+ if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 23) {
+ mDelegateDrawable.getHotspotBounds(outRect);
+ return;
+ }
+ }
+
+ @Override
+ public Rect getDirtyBounds() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getBounds();
+ }
+ return super.getDirtyBounds();
+ }
+
+ @Override
+ public void setFilterBitmap(boolean filter) {
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setFilterBitmap(filter);
+ return;
+ }
+ }
+
+ @TargetApi(23)
+ @Override
+ public boolean isFilterBitmap() {
+ // API >= 23 only
+ if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 23) {
+ return mDelegateDrawable.isFilterBitmap();
+ }
+ return false;
+ }
+
+ @Override
+ public void getOutline(Outline outline) {
+ // API >= 21 only
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.getOutline(outline);
+ return;
+ }
+ }
+
+ @Override
+ public void jumpToCurrentState() {
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.jumpToCurrentState();
+ return;
+ }
+ }
+
+ @Override
+ public void setAutoMirrored(boolean mirrored) {
+ // API >= 21 only.
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setAutoMirrored(mirrored);
+ return;
+ }
+ }
+
+ @Override
+ public boolean isAutoMirrored() {
+ // API >= 21 only.
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.isAutoMirrored();
+ }
+ return false;
+ }
+
+ @Override
+ public void applyTheme(Resources.Theme t) {
+ // API >= 21 only.
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.applyTheme(t);
+ return;
+ }
+ }
+
+ @TargetApi(23)
+ @Override
+ public int getLayoutDirection() {
+ if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 23) {
+ return mDelegateDrawable.getLayoutDirection();
+ }
+ return View.LAYOUT_DIRECTION_LTR;
+ }
+
+ @TargetApi(23)
+ @Override
+ public boolean onLayoutDirectionChanged(int layoutDirection) {
+ if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 23) {
+ return mDelegateDrawable.onLayoutDirectionChanged(layoutDirection);
+ }
+ return false;
+ }
+
+ @Override
+ public void clearColorFilter() {
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.clearColorFilter();
+ return;
+ }
+ super.clearColorFilter();
+ }
+
+ @Override
+ public Drawable getCurrent() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getCurrent();
+ }
+ return super.getCurrent();
+ }
+
+ @Override
+ public int getMinimumWidth() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getMinimumWidth();
+ }
+ return super.getMinimumWidth();
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getMinimumHeight();
+ }
+ return super.getMinimumHeight();
+ }
+
+ @Override
+ public boolean getPadding(Rect padding) {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getPadding(padding);
+ }
+ return super.getPadding(padding);
+ }
+
+ @Override
+ public int[] getState() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getState();
+ }
+ return super.getState();
+ }
+
+
+ @Override
+ public Region getTransparentRegion() {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.getTransparentRegion();
+ }
+ return super.getTransparentRegion();
+ }
+
+ @Override
+ public void setChangingConfigurations(int configs) {
+ if (mDelegateDrawable != null) {
+ mDelegateDrawable.setChangingConfigurations(configs);
+ return;
+ }
+ super.setChangingConfigurations(configs);
+ }
+
+ @Override
+ public boolean setState(int[] stateSet) {
+ if (mDelegateDrawable != null) {
+ return mDelegateDrawable.setState(stateSet);
+ }
+ return super.setState(stateSet);
+ }
+}
diff --git a/graphics/drawable/res/values/attrs.xml b/graphics/drawable/res/values/attrs.xml
deleted file mode 100644
index b54c9a6..0000000
--- a/graphics/drawable/res/values/attrs.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?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/static/src/android/support/graphics/drawable/VectorDrawableCompat.java b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
index 9ca398f..e351031 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -36,9 +36,9 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Build;
+import android.support.annotation.DrawableRes;
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;
@@ -182,7 +182,7 @@
* </pre></li>
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class VectorDrawableCompat extends Drawable {
+public class VectorDrawableCompat extends VectorDrawableCommon {
static final String LOGTAG = "VectorDrawableCompat";
static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
@@ -213,9 +213,6 @@
// caching the bitmap by default is allowed.
private boolean mAllowCaching = true;
- // Drawable delegation for Lollipop and above.
- VectorDrawable mDelegateDrawable;
-
// The Constant state associated with the <code>mDelegateDrawable</code>.
private ConstantState mCachedConstantStateDelegate;
@@ -522,19 +519,6 @@
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 {
@@ -638,7 +622,7 @@
// shown up from API 11.
final float alphaInFloat = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
- AndroidResources.styleable_VectorDrawable_alpha, pathRenderer.getAlpha());
+ AndroidResources.styleable_VectorDrawable_alpha, pathRenderer.getAlpha());
pathRenderer.setAlpha(alphaInFloat);
final String name = a.getString(AndroidResources.styleable_VectorDrawable_name);
@@ -749,15 +733,6 @@
// Extra override functions for delegation for SDK >= 7.
@Override
- public void clearColorFilter() {
- if (mDelegateDrawable != null) {
- mDelegateDrawable.clearColorFilter();
- return;
- }
- super.clearColorFilter();
- }
-
- @Override
public void setBounds(int left, int top, int right, int bottom) {
if (mDelegateDrawable != null) {
mDelegateDrawable.setBounds(left, top, right, bottom);
@@ -784,55 +759,6 @@
}
@Override
- public Drawable getCurrent() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getCurrent();
- }
- return super.getCurrent();
- }
-
- @Override
- public int getMinimumWidth() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getMinimumWidth();
- }
- return super.getMinimumWidth();
- }
-
- @Override
- public int getMinimumHeight() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getMinimumHeight();
- }
- return super.getMinimumHeight();
- }
-
- @Override
- public boolean getPadding(Rect padding) {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getPadding(padding);
- }
- return super.getPadding(padding);
- }
-
- @Override
- public int[] getState() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getState();
- }
- return super.getState();
- }
-
-
- @Override
- public Region getTransparentRegion() {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.getTransparentRegion();
- }
- return super.getTransparentRegion();
- }
-
- @Override
public void invalidateSelf() {
if (mDelegateDrawable != null) {
mDelegateDrawable.invalidateSelf();
@@ -851,23 +777,6 @@
}
@Override
- public void setChangingConfigurations(int configs) {
- if (mDelegateDrawable != null) {
- mDelegateDrawable.setChangingConfigurations(configs);
- return;
- }
- super.setChangingConfigurations(configs);
- }
-
- @Override
- public boolean setState(int[] stateSet) {
- if (mDelegateDrawable != null) {
- return mDelegateDrawable.setState(stateSet);
- }
- return super.setState(stateSet);
- }
-
- @Override
public boolean setVisible(boolean visible, boolean restart) {
if (mDelegateDrawable != null) {
return mDelegateDrawable.setVisible(visible, restart);
diff --git a/graphics/drawable/testanimated/Android.mk b/graphics/drawable/testanimated/Android.mk
index 004cddb..f4d6269 100644
--- a/graphics/drawable/testanimated/Android.mk
+++ b/graphics/drawable/testanimated/Android.mk
@@ -22,10 +22,6 @@
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
diff --git a/graphics/drawable/teststatic/Android.mk b/graphics/drawable/teststatic/Android.mk
index 4c4a7ba..48322c7 100644
--- a/graphics/drawable/teststatic/Android.mk
+++ b/graphics/drawable/teststatic/Android.mk
@@ -22,10 +22,6 @@
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
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
index 1762c15..e9f8505 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/FadeAndShortSlide.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.TimeInterpolator;
+import android.graphics.Rect;
import android.transition.Fade;
import android.transition.Transition;
import android.transition.TransitionValues;
@@ -38,54 +39,101 @@
private static final String PROPNAME_SCREEN_POSITION =
"android:fadeAndShortSlideTransition:screenPosition";
- private CalculateSlide mSlideCalculator = sCalculateEnd;
+ private CalculateSlide mSlideCalculator;
private Visibility mFade = new Fade();
+ private float mDistance = -1;
- private interface CalculateSlide {
+ private static abstract class CalculateSlide {
- /** Returns the translation value for view when it goes out of the scene */
- float getGoneX(ViewGroup sceneRoot, View view, int[] position);
+ /** Returns the translation X value for view when it goes out of the scene */
+ float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
+ return view.getTranslationX();
+ }
+
+ /** Returns the translation Y value for view when it goes out of the scene */
+ float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
+ return view.getTranslationY();
+ }
}
- private static final CalculateSlide sCalculateStart = new CalculateSlide() {
+ float getHorizontalDistance(ViewGroup sceneRoot) {
+ return mDistance >= 0 ? mDistance : (sceneRoot.getWidth() / 4);
+ }
+
+ float getVerticalDistance(ViewGroup sceneRoot) {
+ return mDistance >= 0 ? mDistance : (sceneRoot.getHeight() / 4);
+ }
+
+ final static CalculateSlide sCalculateStart = new CalculateSlide() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+ public float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final float x;
if (isRtl) {
- x = view.getTranslationX() + sceneRoot.getWidth() / 4;
+ x = view.getTranslationX() + t.getHorizontalDistance(sceneRoot);
} else {
- x = view.getTranslationX() - sceneRoot.getWidth() / 4;
+ x = view.getTranslationX() - t.getHorizontalDistance(sceneRoot);
}
return x;
}
};
- private static final CalculateSlide sCalculateEnd = new CalculateSlide() {
+ final static CalculateSlide sCalculateEnd = new CalculateSlide() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+ public float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
final boolean isRtl = sceneRoot.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
final float x;
if (isRtl) {
- x = view.getTranslationX() - sceneRoot.getWidth() / 4;
+ x = view.getTranslationX() - t.getHorizontalDistance(sceneRoot);
} else {
- x = view.getTranslationX() + sceneRoot.getWidth() / 4;
+ x = view.getTranslationX() + t.getHorizontalDistance(sceneRoot);
}
return x;
}
};
- private static final CalculateSlide sCalculateBoth = new CalculateSlide() {
-
+ final static CalculateSlide sCalculateStartEnd = new CalculateSlide() {
@Override
- public float getGoneX(ViewGroup sceneRoot, View view, int[] position) {
+ public float getGoneX(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
final int viewCenter = position[0] + view.getWidth() / 2;
sceneRoot.getLocationOnScreen(position);
- final int sceneRootCenter = position[0] + sceneRoot.getWidth() / 2;
+ Rect center = t.getEpicenter();
+ final int sceneRootCenter = center == null ? (position[0] + sceneRoot.getWidth() / 2)
+ : center.centerX();
if (viewCenter < sceneRootCenter) {
- return view.getTranslationX() - sceneRoot.getWidth() / 2;
+ return view.getTranslationX() - t.getHorizontalDistance(sceneRoot);
} else {
- return view.getTranslationX() + sceneRoot.getWidth() / 2;
+ return view.getTranslationX() + t.getHorizontalDistance(sceneRoot);
+ }
+ }
+ };
+
+ final static CalculateSlide sCalculateBottom = new CalculateSlide() {
+ @Override
+ public float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
+ return view.getTranslationY() + t.getVerticalDistance(sceneRoot);
+ }
+ };
+
+ final static CalculateSlide sCalculateTop = new CalculateSlide() {
+ @Override
+ public float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
+ return view.getTranslationY() - t.getVerticalDistance(sceneRoot);
+ }
+ };
+
+ final CalculateSlide sCalculateTopBottom = new CalculateSlide() {
+ @Override
+ public float getGoneY(FadeAndShortSlide t, ViewGroup sceneRoot, View view, int[] position) {
+ final int viewCenter = position[1] + view.getHeight() / 2;
+ sceneRoot.getLocationOnScreen(position);
+ Rect center = getEpicenter();
+ final int sceneRootCenter = center == null ? (position[1] + sceneRoot.getHeight() / 2)
+ : center.centerY();
+ if (viewCenter < sceneRootCenter) {
+ return view.getTranslationY() - t.getVerticalDistance(sceneRoot);
+ } else {
+ return view.getTranslationY() + t.getVerticalDistance(sceneRoot);
}
}
};
@@ -134,7 +182,16 @@
mSlideCalculator = sCalculateEnd;
break;
case Gravity.START | Gravity.END:
- mSlideCalculator = sCalculateBoth;
+ mSlideCalculator = sCalculateStartEnd;
+ break;
+ case Gravity.TOP:
+ mSlideCalculator = sCalculateTop;
+ break;
+ case Gravity.BOTTOM:
+ mSlideCalculator = sCalculateBottom;
+ break;
+ case Gravity.TOP | Gravity.BOTTOM:
+ mSlideCalculator = sCalculateTopBottom;
break;
default:
throw new IllegalArgumentException("Invalid slide direction");
@@ -156,12 +213,21 @@
}
int[] position = (int[]) endValues.values.get(PROPNAME_SCREEN_POSITION);
int left = position[0];
+ int top = position[1];
float endX = view.getTranslationX();
- float startX = mSlideCalculator.getGoneX(sceneRoot, view, position);
+ float startX = mSlideCalculator.getGoneX(this, sceneRoot, view, position);
+ float endY = view.getTranslationY();
+ float startY = mSlideCalculator.getGoneY(this, sceneRoot, view, position);
final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view, endValues,
- left, startX, endX, sDecelerate, this);
+ left, top, startX, startY, endX, endY, sDecelerate, this);
+ final Animator fadeAnimator = mFade.onAppear(sceneRoot, view, startValues, endValues);
+ if (slideAnimator == null) {
+ return fadeAnimator;
+ } else if (fadeAnimator == null) {
+ return slideAnimator;
+ }
final AnimatorSet set = new AnimatorSet();
- set.play(slideAnimator).with(mFade.onAppear(sceneRoot, view, startValues, endValues));
+ set.play(slideAnimator).with(fadeAnimator);
return set;
}
@@ -178,12 +244,22 @@
}
int[] position = (int[]) startValues.values.get(PROPNAME_SCREEN_POSITION);
int left = position[0];
+ int top = position[1];
float startX = view.getTranslationX();
- float endX = mSlideCalculator.getGoneX(sceneRoot, view, position);
+ float endX = mSlideCalculator.getGoneX(this, sceneRoot, view, position);
+ float startY = view.getTranslationY();
+ float endY = mSlideCalculator.getGoneY(this, sceneRoot, view, position);
final Animator slideAnimator = TranslationAnimationCreator.createAnimation(view,
- startValues, left, startX, endX, sDecelerate /* sAccelerate */, this);
+ startValues, left, top, startX, startY, endX, endY, sDecelerate /* sAccelerate */,
+ this);
+ final Animator fadeAnimator = mFade.onDisappear(sceneRoot, view, startValues, endValues);
+ if (slideAnimator == null) {
+ return fadeAnimator;
+ } else if (fadeAnimator == null) {
+ return slideAnimator;
+ }
final AnimatorSet set = new AnimatorSet();
- set.play(slideAnimator).with(mFade.onDisappear(sceneRoot, view, startValues, endValues));
+ set.play(slideAnimator).with(fadeAnimator);
return set;
}
@@ -200,6 +276,23 @@
return super.removeListener(listener);
}
+ /**
+ * Returns distance to slide. When negative value is returned, it will use 1/4 of
+ * sceneRoot dimension.
+ */
+ public float getDistance() {
+ return mDistance;
+ }
+
+ /**
+ * Set distance to slide, default value is -1. when negative value is set, it will use 1/4 of
+ * sceneRoot dimension.
+ * @param distance Pixels to slide.
+ */
+ public void setDistance(float distance) {
+ mDistance = distance;
+ }
+
@Override
public Transition clone() {
FadeAndShortSlide clone = null;
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
index c5a33cb..9b27580 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.transition.ChangeTransform;
import android.transition.Transition;
+import android.transition.TransitionManager;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -90,6 +91,17 @@
return new FadeAndShortSlide(edge);
}
+ public static Object createFadeAndShortSlide(int edge, float distance) {
+ FadeAndShortSlide slide = new FadeAndShortSlide(edge);
+ slide.setDistance(distance);
+ return slide;
+ }
+
+ public static void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
+ Transition transition = (Transition) transitionObject;
+ TransitionManager.beginDelayedTransition(sceneRoot, transition);
+ }
+
public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
viewGroup.setTransitionGroup(transitionGroup);
}
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
index 2cc3545..46068da 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TranslationAnimationCreator.java
@@ -9,54 +9,60 @@
import android.graphics.Path;
import android.transition.Transition;
import android.transition.TransitionValues;
+import android.transition.Transition.TransitionListener;
import android.view.View;
/**
- * This class is used by Slide and Explode to create an animator that goes from the start position
- * to the end position. It takes into account the canceled position so that it will not blink out or
- * shift suddenly when the transition is interrupted.
+ * This class is used by Slide and Explode to create an animator that goes from the start
+ * position to the end position. It takes into account the canceled position so that it
+ * will not blink out or shift suddenly when the transition is interrupted.
* @hide
*/
class TranslationAnimationCreator {
/**
- * Creates an animator that can be used for x and/or y translations. When interrupted, it sets a
- * tag to keep track of the position so that it may be continued from position.
+ * Creates an animator that can be used for x and/or y translations. When interrupted,
+ * it sets a tag to keep track of the position so that it may be continued from position.
*
* @param view The view being moved. This may be in the overlay for onDisappear.
* @param values The values containing the view in the view hierarchy.
* @param viewPosX The x screen coordinate of view
+ * @param viewPosY The y screen coordinate of view
* @param startX The start translation x of view
+ * @param startY The start translation y of view
* @param endX The end translation x of view
+ * @param endY The end translation y of view
* @param interpolator The interpolator to use with this animator.
- * @return An animator that moves from (startX, startY) to (endX, endY) unless there was a
- * previous interruption, in which case it moves from the current position to (endX,
- * endY).
+ * @return An animator that moves from (startX, startY) to (endX, endY) unless there was
+ * a previous interruption, in which case it moves from the current position to (endX, endY).
*/
- static Animator createAnimation(View view, TransitionValues values, int viewPosX, float startX,
- float endX, TimeInterpolator interpolator, Transition transition) {
+ static Animator createAnimation(View view, TransitionValues values, int viewPosX, int viewPosY,
+ float startX, float startY, float endX, float endY, TimeInterpolator interpolator,
+ Transition transition) {
float terminalX = view.getTranslationX();
- Integer startPosition = (Integer) values.view.getTag(R.id.transitionPosition);
+ float terminalY = view.getTranslationY();
+ int[] startPosition = (int[]) values.view.getTag(R.id.transitionPosition);
if (startPosition != null) {
- startX = startPosition - viewPosX + terminalX;
+ startX = startPosition[0] - viewPosX + terminalX;
+ startY = startPosition[1] - viewPosY + terminalY;
}
- // Initial position is at translation startX, startY, so position is offset by that
- // amount
+ // Initial position is at translation startX, startY, so position is offset by that amount
int startPosX = viewPosX + Math.round(startX - terminalX);
+ int startPosY = viewPosY + Math.round(startY - terminalY);
view.setTranslationX(startX);
- if (startX == endX) {
+ view.setTranslationY(startY);
+ if (startX == endX && startY == endY) {
return null;
}
- float y = view.getTranslationY();
Path path = new Path();
- path.moveTo(startX, y);
- path.lineTo(endX, y);
- ObjectAnimator anim =
- ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, path);
+ path.moveTo(startX, startY);
+ path.lineTo(endX, endY);
+ ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y,
+ path);
- TransitionPositionListener listener =
- new TransitionPositionListener(view, values.view, startPosX, terminalX);
+ TransitionPositionListener listener = new TransitionPositionListener(view, values.view,
+ startPosX, startPosY, terminalX, terminalY);
transition.addListener(listener);
anim.addListener(listener);
anim.addPauseListener(listener);
@@ -64,23 +70,28 @@
return anim;
}
- private static class TransitionPositionListener extends AnimatorListenerAdapter
- implements Transition.TransitionListener {
+ private static class TransitionPositionListener extends AnimatorListenerAdapter implements
+ TransitionListener {
private final View mViewInHierarchy;
private final View mMovingView;
private final int mStartX;
- private Integer mTransitionPosition;
+ private final int mStartY;
+ private int[] mTransitionPosition;
private float mPausedX;
+ private float mPausedY;
private final float mTerminalX;
+ private final float mTerminalY;
- private TransitionPositionListener(View movingView, View viewInHierarchy, int startX,
- float terminalX) {
+ private TransitionPositionListener(View movingView, View viewInHierarchy,
+ int startX, int startY, float terminalX, float terminalY) {
mMovingView = movingView;
mViewInHierarchy = viewInHierarchy;
mStartX = startX - Math.round(mMovingView.getTranslationX());
+ mStartY = startY - Math.round(mMovingView.getTranslationY());
mTerminalX = terminalX;
- mTransitionPosition = (Integer) mViewInHierarchy.getTag(R.id.transitionPosition);
+ mTerminalY = terminalY;
+ mTransitionPosition = (int[]) mViewInHierarchy.getTag(R.id.transitionPosition);
if (mTransitionPosition != null) {
mViewInHierarchy.setTag(R.id.transitionPosition, null);
}
@@ -88,41 +99,53 @@
@Override
public void onAnimationCancel(Animator animation) {
- mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX());
+ if (mTransitionPosition == null) {
+ mTransitionPosition = new int[2];
+ }
+ mTransitionPosition[0] = Math.round(mStartX + mMovingView.getTranslationX());
+ mTransitionPosition[1] = Math.round(mStartY + mMovingView.getTranslationY());
mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition);
}
@Override
- public void onAnimationEnd(Animator animator) {}
+ public void onAnimationEnd(Animator animator) {
+ }
@Override
public void onAnimationPause(Animator animator) {
mPausedX = mMovingView.getTranslationX();
+ mPausedY = mMovingView.getTranslationY();
mMovingView.setTranslationX(mTerminalX);
+ mMovingView.setTranslationY(mTerminalY);
}
@Override
public void onAnimationResume(Animator animator) {
mMovingView.setTranslationX(mPausedX);
+ mMovingView.setTranslationY(mPausedY);
}
@Override
- public void onTransitionStart(Transition transition) {}
+ public void onTransitionStart(Transition transition) {
+ }
@Override
public void onTransitionEnd(Transition transition) {
mMovingView.setTranslationX(mTerminalX);
+ mMovingView.setTranslationY(mTerminalY);
}
@Override
- public void onTransitionCancel(Transition transition) {}
+ public void onTransitionCancel(Transition transition) {
+ }
@Override
- public void onTransitionPause(Transition transition) {}
+ public void onTransitionPause(Transition transition) {
+ }
@Override
- public void onTransitionResume(Transition transition) {}
+ public void onTransitionResume(Transition transition) {
+ }
}
}
-
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
index 9420154..156ad97 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
@@ -103,6 +103,8 @@
public Object createFadeAndShortSlide(int edge);
+ public Object createFadeAndShortSlide(int edge, float distance);
+
public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay);
public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay);
@@ -146,6 +148,8 @@
public Object loadTransition(Context context, int resId);
+ public void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject);
+
public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup);
}
@@ -238,6 +242,11 @@
}
@Override
+ public Object createFadeAndShortSlide(int edge, float distance) {
+ return new TransitionStub();
+ }
+
+ @Override
public Object createSlide(int slideEdge) {
return new TransitionStub();
}
@@ -360,6 +369,10 @@
}
@Override
+ public void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
+ }
+
+ @Override
public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
}
}
@@ -552,6 +565,16 @@
}
@Override
+ public Object createFadeAndShortSlide(int edge, float distance) {
+ return TransitionHelperApi21.createFadeAndShortSlide(edge, distance);
+ }
+
+ @Override
+ public void beginDelayedTransition(ViewGroup sceneRoot, Object transition) {
+ TransitionHelperApi21.beginDelayedTransition(sceneRoot, transition);
+ }
+
+ @Override
public Object getEnterTransition(Window window) {
return TransitionHelperApi21.getEnterTransition(window);
}
@@ -780,6 +803,14 @@
return sImpl.createFadeAndShortSlide(edge);
}
+ public static Object createFadeAndShortSlide(int edge, float distance) {
+ return sImpl.createFadeAndShortSlide(edge, distance);
+ }
+
+ public static void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
+ sImpl.beginDelayedTransition(sceneRoot, transitionObject);
+ }
+
public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
sImpl.setTransitionGroup(viewGroup, transitionGroup);
}
diff --git a/v4/java/android/support/v4/media/session/MediaSessionCompat.java b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
index d35ada6..4980a9f 100644
--- a/v4/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/v4/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
@@ -1303,8 +1304,42 @@
}
}
+ /**
+ * Clones the given {@link MediaMetadataCompat}, deep-copying bitmaps in the metadata if
+ * they exist. If there is no bitmap in the metadata, this method just returns the given
+ * metadata.
+ *
+ * @param metadata A {@link MediaMetadataCompat} to be cloned.
+ * @return A newly cloned metadata if it contains bitmaps. Otherwise, the given metadata
+ * will be returned.
+ */
+ private MediaMetadataCompat cloneMetadataIfNeeded(MediaMetadataCompat metadata) {
+ if (metadata == null) {
+ return null;
+ } else if (!metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ART)
+ && !metadata.containsKey(MediaMetadataCompat.METADATA_KEY_ALBUM_ART)) {
+ return metadata;
+ }
+ MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(metadata);
+ Bitmap artBitmap = metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ART);
+ if (artBitmap != null) {
+ builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART,
+ artBitmap.copy(artBitmap.getConfig(), false));
+ }
+ Bitmap albumArtBitmap = metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART);
+ if (albumArtBitmap != null) {
+ builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
+ albumArtBitmap.copy(albumArtBitmap.getConfig(), false));
+ }
+ return builder.build();
+ }
+
@Override
public void setMetadata(MediaMetadataCompat metadata) {
+ if (android.os.Build.VERSION.SDK_INT >= 14 && metadata != null) {
+ // Clone bitmaps in metadata for protecting them to be recycled by RCC.
+ metadata = cloneMetadataIfNeeded(metadata);
+ }
synchronized (mLock) {
mMetadata = metadata;
}
diff --git a/v4/tests/AndroidManifest.xml b/v4/tests/AndroidManifest.xml
index b80e400..cfd6406 100644
--- a/v4/tests/AndroidManifest.xml
+++ b/v4/tests/AndroidManifest.xml
@@ -22,6 +22,11 @@
android:targetSdkVersion="23"
tools:overrideLibrary="android.support.test,android.support.test.espresso, android.support.test.espresso.idling"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.READ_CONTACTS"/>
+ <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
<application android:supportsRtl="true">
<uses-library android:name="android.test.runner" />
<activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
diff --git a/v4/tests/java/android/support/v4/content/ContextCompatTest.java b/v4/tests/java/android/support/v4/content/ContextCompatTest.java
index 8f3cd04..e2fc0b7 100644
--- a/v4/tests/java/android/support/v4/content/ContextCompatTest.java
+++ b/v4/tests/java/android/support/v4/content/ContextCompatTest.java
@@ -17,6 +17,7 @@
import android.content.res.ColorStateList;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.ThemedYellowActivity;
@@ -40,8 +41,8 @@
public void testGetColor() throws Throwable {
Context context = getActivity();
- assertEquals("Unthemed color load",
- ContextCompat.getColor(context, R.color.text_color), 0xFFFF8090);
+ assertEquals("Unthemed color load", 0xFFFF8090,
+ ContextCompat.getColor(context, R.color.text_color));
if (Build.VERSION.SDK_INT >= 23) {
// The following test is only expected to pass on v23+ devices. The result of
@@ -59,28 +60,28 @@
ColorStateList unthemedColorStateList =
ContextCompat.getColorStateList(context, R.color.complex_unthemed_selector);
- assertEquals("Unthemed color state list load: default",
- unthemedColorStateList.getDefaultColor(), 0xFF70A0C0);
- assertEquals("Unthemed color state list load: focused",
+ assertEquals("Unthemed color state list load: default", 0xFF70A0C0,
+ unthemedColorStateList.getDefaultColor());
+ assertEquals("Unthemed color state list load: focused", 0xFF70B0F0,
unthemedColorStateList.getColorForState(
- new int[] {android.R.attr.state_focused}, 0), 0xFF70B0F0);
- assertEquals("Unthemed color state list load: pressed",
+ new int[]{android.R.attr.state_focused}, 0));
+ assertEquals("Unthemed color state list load: pressed", 0xFF6080B0,
unthemedColorStateList.getColorForState(
- new int[] {android.R.attr.state_pressed}, 0), 0xFF6080B0);
+ new int[]{android.R.attr.state_pressed}, 0));
if (Build.VERSION.SDK_INT >= 23) {
// The following tests are only expected to pass on v23+ devices. The result of
// calling theme-aware getColorStateList() in pre-v23 is undefined.
ColorStateList themedYellowColorStateList =
ContextCompat.getColorStateList(context, R.color.complex_themed_selector);
- assertEquals("Themed yellow color state list load: default",
- themedYellowColorStateList.getDefaultColor(), 0xFFF0B000);
- assertEquals("Themed yellow color state list load: focused",
+ assertEquals("Themed yellow color state list load: default", 0xFFF0B000,
+ themedYellowColorStateList.getDefaultColor());
+ assertEquals("Themed yellow color state list load: focused", 0xFFF0A020,
themedYellowColorStateList.getColorForState(
- new int[]{android.R.attr.state_focused}, 0), 0xFFF0A020);
- assertEquals("Themed yellow color state list load: pressed",
+ new int[]{android.R.attr.state_focused}, 0));
+ assertEquals("Themed yellow color state list load: pressed", 0xFFE0A040,
themedYellowColorStateList.getColorForState(
- new int[]{android.R.attr.state_pressed}, 0), 0xFFE0A040);
+ new int[]{android.R.attr.state_pressed}, 0));
}
}
@@ -103,4 +104,62 @@
themedYellowDrawable, 0xFFF0B000);
}
}
-}
+
+
+ @UiThreadTest
+ @SmallTest
+ public void testCheckSelfPermission() throws Throwable {
+ Context context = getActivity();
+
+ try {
+ ContextCompat.checkSelfPermission(context, null);
+ fail("Should have thrown an exception on null parameter");
+ } catch (IllegalArgumentException iae) {
+ // This is the expected condition - just ignore and continue with the rest of the
+ // tests in this method.
+ }
+
+ assertEquals("Vibrate permission granted", PackageManager.PERMISSION_GRANTED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.VIBRATE));
+ assertEquals("Wake lock permission granted", PackageManager.PERMISSION_GRANTED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.WAKE_LOCK));
+
+ if (Build.VERSION.SDK_INT >= 23) {
+ // As documented in http://developer.android.com/training/permissions/requesting.html
+ // starting in Android M (v23) dangerous permissions are not granted automactically
+ // to apps targeting SDK 23 even if those are defined in the manifest.
+ // This is why the following permissions are expected to be denied.
+ assertEquals("Read contacts permission granted", PackageManager.PERMISSION_DENIED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.READ_CONTACTS));
+ assertEquals("Write contacts permission granted", PackageManager.PERMISSION_DENIED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.WRITE_CONTACTS));
+ } else {
+ // And on older devices declared dangerous permissions are expected to be granted.
+ assertEquals("Read contacts permission denied", PackageManager.PERMISSION_GRANTED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.READ_CONTACTS));
+ assertEquals("Write contacts permission denied", PackageManager.PERMISSION_GRANTED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.WRITE_CONTACTS));
+ }
+
+ // The following permissions (normal and dangerous) are expected to be denied as they are
+ // not declared in our manifest.
+ assertEquals("Access network state permission denied", PackageManager.PERMISSION_DENIED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.ACCESS_NETWORK_STATE));
+ assertEquals("Bluetooth permission denied", PackageManager.PERMISSION_DENIED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.BLUETOOTH));
+ assertEquals("Call phone permission denied", PackageManager.PERMISSION_DENIED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.CALL_PHONE));
+ assertEquals("Delete packages permission denied", PackageManager.PERMISSION_DENIED,
+ ContextCompat.checkSelfPermission(context,
+ android.Manifest.permission.DELETE_PACKAGES));
+ }
+}
\ No newline at end of file
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
index 5856f38..bc961a7 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
@@ -25,6 +25,7 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
@@ -72,6 +73,8 @@
private RouteAdapter mAdapter;
private ListView mListView;
private boolean mAttachedToWindow;
+ private AsyncTask<Void, Void, Void> mRefreshRoutesTask;
+ private AsyncTask<Void, Void, Void> mOnItemClickTask;
public MediaRouteChooserDialog(Context context) {
this(context, 0);
@@ -197,12 +200,39 @@
*/
public void refreshRoutes() {
if (mAttachedToWindow) {
- mRoutes.clear();
- mRoutes.addAll(mRouter.getRoutes());
- onFilterRoutes(mRoutes);
- RouteComparator.loadRouteUsageScores(getContext(), mRoutes);
- Collections.sort(mRoutes, RouteComparator.sInstance);
- mAdapter.notifyDataSetChanged();
+ if (mRefreshRoutesTask != null) {
+ mRefreshRoutesTask.cancel(true);
+ mRefreshRoutesTask = null;
+ }
+ mRefreshRoutesTask = new AsyncTask<Void, Void, Void>() {
+ private ArrayList<MediaRouter.RouteInfo> mNewRoutes;
+
+ @Override
+ protected void onPreExecute() {
+ mNewRoutes = new ArrayList<>(mRouter.getRoutes());
+ onFilterRoutes(mNewRoutes);
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ // In API 4 ~ 10, AsyncTasks are running in parallel. Needs synchronization.
+ synchronized (MediaRouteChooserDialog.this) {
+ if (!isCancelled()) {
+ RouteComparator.loadRouteUsageScores(getContext(), mNewRoutes);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void params) {
+ mRoutes.clear();
+ mRoutes.addAll(mNewRoutes);
+ Collections.sort(mRoutes, RouteComparator.sInstance);
+ mAdapter.notifyDataSetChanged();
+ mRefreshRoutesTask = null;
+ }
+ }.execute();
}
}
@@ -277,11 +307,26 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- MediaRouter.RouteInfo route = getItem(position);
- if (route.isEnabled()) {
- route.select();
- RouteComparator.storeRouteUsageScores(getContext(), route.getId());
- dismiss();
+ final MediaRouter.RouteInfo route = getItem(position);
+ if (route.isEnabled() && mOnItemClickTask == null) {
+ mOnItemClickTask = new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected void onPreExecute() {
+ route.select();
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ RouteComparator.storeRouteUsageScores(getContext(), route.getId());
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void params) {
+ dismiss();
+ mOnItemClickTask = null;
+ }
+ }.execute();
}
}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index 1f375a0..0e38e33 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -62,10 +62,14 @@
import android.widget.TextView;
import java.io.BufferedInputStream;
+import java.io.InputStream;
import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
* This class implements the route controller dialog for {@link MediaRouter}.
@@ -83,6 +87,7 @@
// to allow the route provider time to propagate the change and publish a new
// route descriptor.
private static final int VOLUME_UPDATE_DELAY_MILLIS = 500;
+ private static final int CONNECTION_TIMEOUT_MILLIS = (int) TimeUnit.SECONDS.toMillis(30L);
private static final int BUTTON_NEUTRAL_RES_ID = android.R.id.button3;
private static final int BUTTON_DISCONNECT_RES_ID = android.R.id.button2;
@@ -759,6 +764,15 @@
view.setLayoutParams(lp);
}
+ private static boolean uriEquals(Uri uri1, Uri uri2) {
+ if (uri1 != null && uri1.equals(uri2)) {
+ return true;
+ } else if (uri1 == null && uri2 == null) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Returns desired art height to fit into controller dialog.
*/
@@ -955,7 +969,7 @@
@Override
protected void onPreExecute() {
- if (mArtIconBitmap == mIconBitmap && mArtIconUri == mIconUri) {
+ if (!isIconChanged()) {
// Already handled the current art.
cancel(true);
}
@@ -967,18 +981,12 @@
if (mIconBitmap != null) {
art = mIconBitmap;
} else if (mIconUri != null) {
- String scheme = mIconUri.getScheme();
- if (!(ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
- || ContentResolver.SCHEME_CONTENT.equals(scheme)
- || ContentResolver.SCHEME_FILE.equals(scheme))) {
- Log.w(TAG, "Icon Uri should point to local resources.");
- return null;
- }
- BufferedInputStream stream = null;
+ InputStream stream = null;
try {
- stream = new BufferedInputStream(
- mContext.getContentResolver().openInputStream(mIconUri));
-
+ if ((stream = openInputStreamByScheme(mIconUri)) == null) {
+ Log.w(TAG, "Unable to open: " + mIconUri);
+ return null;
+ }
// Query art size.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
@@ -992,8 +1000,10 @@
} catch (IOException e) {
// Failed to rewind the stream, try to reopen it.
stream.close();
- stream = new BufferedInputStream(mContext.getContentResolver()
- .openInputStream(mIconUri));
+ if ((stream = openInputStreamByScheme(mIconUri)) == null) {
+ Log.w(TAG, "Unable to open: " + mIconUri);
+ return null;
+ }
}
// Calculate required size to decode the art and possibly resize it.
options.inJustDecodeBounds = false;
@@ -1041,5 +1051,36 @@
updateLayoutHeight();
}
}
+
+ /**
+ * Returns whether a new art image is different from an original art image. Compares
+ * Bitmap objects first, and then compares URIs only if bitmap is unchanged with
+ * a null value.
+ */
+ private boolean isIconChanged() {
+ if (mIconBitmap != mArtIconBitmap) {
+ return true;
+ } else if (mIconBitmap == null && !uriEquals(mIconUri, mArtIconUri)) {
+ return true;
+ }
+ return false;
+ }
+
+ private InputStream openInputStreamByScheme(Uri uri) throws IOException {
+ String scheme = uri.getScheme().toLowerCase();
+ InputStream stream = null;
+ if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+ || ContentResolver.SCHEME_CONTENT.equals(scheme)
+ || ContentResolver.SCHEME_FILE.equals(scheme)) {
+ stream = mContext.getContentResolver().openInputStream(uri);
+ } else {
+ URL url = new URL(uri.toString());
+ URLConnection conn = url.openConnection();
+ conn.setConnectTimeout(CONNECTION_TIMEOUT_MILLIS);
+ conn.setReadTimeout(CONNECTION_TIMEOUT_MILLIS);
+ stream = conn.getInputStream();
+ }
+ return (stream == null) ? null : new BufferedInputStream(stream);
+ }
}
}
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 57684f8..c956a2e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -4961,7 +4961,7 @@
final int cachedCount = mCachedViews.size();
for (int i = 0; i < cachedCount; i++) {
final ViewHolder holder = mCachedViews.get(i);
- if (holder != null && holder.getLayoutPosition() >= insertedAt) {
+ if (holder != null && holder.mPosition >= insertedAt) {
if (DEBUG) {
Log.d(TAG, "offsetPositionRecordsForInsert cached " + i + " holder " +
holder + " now at position " + (holder.mPosition + count));
@@ -4983,14 +4983,14 @@
for (int i = cachedCount - 1; i >= 0; i--) {
final ViewHolder holder = mCachedViews.get(i);
if (holder != null) {
- if (holder.getLayoutPosition() >= removedEnd) {
+ if (holder.mPosition >= removedEnd) {
if (DEBUG) {
Log.d(TAG, "offsetPositionRecordsForRemove cached " + i +
" holder " + holder + " now at position " +
(holder.mPosition - count));
}
holder.offsetPosition(-count, applyToPreLayout);
- } else if (holder.getLayoutPosition() >= removedFrom) {
+ } else if (holder.mPosition >= removedFrom) {
// Item for this view was removed. Dump it from the cache.
holder.addFlags(ViewHolder.FLAG_REMOVED);
recycleCachedViewAt(i);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
index 06dcbb0..917680b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
@@ -28,6 +28,8 @@
import android.view.ViewGroup;
import android.widget.TextView;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
public class RecyclerViewBasicTest extends AndroidTestCase {
@@ -170,6 +172,49 @@
adapterNew, null);
}
+ public void testRecyclerOffsetsOnMove() {
+ MockLayoutManager layoutManager = new MockLayoutManager();
+ final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>();
+ mRecyclerView.setLayoutManager(layoutManager);
+ MockAdapter adapter = new MockAdapter(100) {
+ @Override
+ public void onViewRecycled(RecyclerView.ViewHolder holder) {
+ super.onViewRecycled(holder);
+ recycledVhs.add(holder);
+ }
+ };
+ MockViewHolder mvh = new MockViewHolder(new TextView(getContext()));
+ mRecyclerView.setAdapter(adapter);
+ adapter.bindViewHolder(mvh, 20);
+ mRecyclerView.mRecycler.mCachedViews.add(mvh);
+ mRecyclerView.offsetPositionRecordsForRemove(10, 9, false);
+
+ mRecyclerView.offsetPositionRecordsForRemove(11, 1, false);
+ assertEquals(1, recycledVhs.size());
+ assertSame(mvh, recycledVhs.get(0));
+ }
+
+ public void testRecyclerOffsetsOnAdd() {
+ MockLayoutManager layoutManager = new MockLayoutManager();
+ final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>();
+ mRecyclerView.setLayoutManager(layoutManager);
+ MockAdapter adapter = new MockAdapter(100) {
+ @Override
+ public void onViewRecycled(RecyclerView.ViewHolder holder) {
+ super.onViewRecycled(holder);
+ recycledVhs.add(holder);
+ }
+ };
+ MockViewHolder mvh = new MockViewHolder(new TextView(getContext()));
+ mRecyclerView.setAdapter(adapter);
+ adapter.bindViewHolder(mvh, 20);
+ mRecyclerView.mRecycler.mCachedViews.add(mvh);
+ mRecyclerView.offsetPositionRecordsForRemove(10, 9, false);
+
+ mRecyclerView.offsetPositionRecordsForInsert(15, 10);
+ assertEquals(11, mvh.mPosition);
+ }
+
public void testSavedStateWithStatelessLayoutManager() throws InterruptedException {
mRecyclerView.setLayoutManager(new MockLayoutManager() {
@Override