Updates documentation for MessagingStyle constructor
am: 5c45c3ad1a
Change-Id: Iebc4a18ca6e07cfc46f4d35f756343e7aabc8f08
diff --git a/compat/java/android/support/v4/app/ActivityCompat.java b/compat/java/android/support/v4/app/ActivityCompat.java
index c30e49d..3888be9 100644
--- a/compat/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/java/android/support/v4/app/ActivityCompat.java
@@ -29,6 +29,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Parcelable;
+import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
@@ -330,8 +331,8 @@
* 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[]).
+ * activity stack before delivering the result to your
+ * {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}.
* </p>
* <p>
* When checking whether you have a permission you should use {@link
@@ -343,18 +344,30 @@
* can be useful if the way your app uses the data guarded by the permissions
* changes significantly.
* </p>
+ * <p>
+ * You cannot request a permission if your activity sets {@link
+ * android.R.attr#noHistory noHistory} to <code>true</code> in the manifest
+ * because in this case the activity would not receive result callbacks including
+ * {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}.
+ * </p>
+ * <p>
+ * The <a href="http://developer.android.com/samples/RuntimePermissions/index.html">
+ * RuntimePermissions</a> sample app demonstrates how to use this method to
+ * request permissions at run time.
+ * </p>
*
* @param activity The target activity.
- * @param permissions The requested permissions.
+ * @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
- * reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
- * int, String[], int[])}.
+ * reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(int, String[], int[])}.
+ * Should be >= 0.
*
+ * @see 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) {
+ final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode) {
if (Build.VERSION.SDK_INT >= 23) {
ActivityCompatApi23.requestPermissions(activity, permissions, requestCode);
} else if (activity instanceof OnRequestPermissionsResultCallback) {
diff --git a/compat/java/android/support/v4/content/ModernAsyncTask.java b/compat/java/android/support/v4/content/ModernAsyncTask.java
index bb80bb6..7e95da6 100644
--- a/compat/java/android/support/v4/content/ModernAsyncTask.java
+++ b/compat/java/android/support/v4/content/ModernAsyncTask.java
@@ -16,6 +16,15 @@
package android.support.v4.content;
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.support.annotation.RestrictTo;
+
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
@@ -30,15 +39,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.support.annotation.RestrictTo;
-
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
/**
* Copy of the required parts of {@link android.os.AsyncTask} from Android 3.0 that is
* needed to support AsyncTaskLoader. We use this rather than the one from the platform
@@ -86,7 +86,8 @@
private volatile Status mStatus = Status.PENDING;
- final AtomicBoolean mTaskInvoked = new AtomicBoolean();
+ private final AtomicBoolean mCancelled = new AtomicBoolean();
+ private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
/**
* Indicates the current status of the task. Each status will be set only once
@@ -136,6 +137,9 @@
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
+ } catch (Throwable tr) {
+ mCancelled.set(true);
+ throw tr;
} finally {
postResult(result);
}
@@ -289,7 +293,7 @@
* @see #cancel(boolean)
*/
public final boolean isCancelled() {
- return mFuture.isCancelled();
+ return mCancelled.get();
}
/**
@@ -322,6 +326,7 @@
* @see #onCancelled(Object)
*/
public final boolean cancel(boolean mayInterruptIfRunning) {
+ mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
diff --git a/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java b/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
index fc144c5..3e13f44 100644
--- a/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
+++ b/compat/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.fail;
+import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
@@ -26,6 +27,7 @@
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@@ -76,4 +78,53 @@
fail("onCancelled not called!");
}
}
+
+ /**
+ * Test to ensure that onCancelled is always called instead of onPostExecute when the exception
+ * is not suppressed by cancelling the task.
+ *
+ * @throws Throwable
+ */
+ @LargeTest
+ @Test
+ public void testException() throws Throwable {
+ final CountDownLatch calledOnCancelled = new CountDownLatch(1);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mModernAsyncTask = new ModernAsyncTask() {
+ @Override
+ protected Object doInBackground(Object[] params) {
+ throw new RuntimeException();
+ }
+
+ @Override
+ protected void onPostExecute(Object o) {
+ fail("onPostExecute should not be called");
+ }
+
+ @Override
+ protected void onCancelled(Object o) {
+ calledOnCancelled.countDown();
+ }
+ };
+ }
+ });
+
+ mModernAsyncTask.executeOnExecutor(new Executor() {
+ @Override
+ public void execute(@NonNull Runnable command) {
+ try {
+ command.run();
+ fail("Exception not thrown");
+ } catch (Throwable tr) {
+ // expected
+ }
+ }
+ });
+
+ if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) {
+ fail("onCancelled not called");
+ }
+ }
}
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index f916e5f..9566934 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -1309,6 +1309,12 @@
}
private void offsetChildByInset(final View child, final Rect inset, final int layoutDirection) {
+ if (!ViewCompat.isLaidOut(child)) {
+ // The view has not been laid out yet,
+ // so we can't obtain its bounds.
+ return;
+ }
+
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int absDodgeInsetEdges = GravityCompat.getAbsoluteGravity(lp.dodgeInsetEdges,
layoutDirection);
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 40adf2d..3355956 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -93,6 +93,12 @@
*
* </android.support.design.widget.TextInputLayout>
* </pre>
+ *
+ * <p><strong>Note:</strong> The actual view hierarchy present under TextInputLayout is
+ * <strong>NOT</strong> guaranteed to match the view hierarchy as written in XML. As a result,
+ * calls to getParent() on children of the TextInputLayout -- such as an TextInputEditText --
+ * may not return the TextInputLayout itself, but rather an intermediate View. If you need
+ * to access a View directly, set an {@code android:id} and use {@link View#findViewById(int)}.
*/
public class TextInputLayout extends LinearLayout {
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index f6350c1..9fff6a2 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -31,7 +31,9 @@
import static org.mockito.Mockito.verify;
import android.app.Instrumentation;
+import android.graphics.Rect;
import android.support.design.testutils.CoordinatorLayoutUtils;
+import android.support.design.widget.CoordinatorLayout.Behavior;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.v4.view.ViewCompat;
@@ -39,7 +41,9 @@
import android.test.suitebuilder.annotation.MediumTest;
import android.view.Gravity;
import android.view.View;
+import android.view.View.MeasureSpec;
+import org.junit.Before;
import org.junit.Test;
import java.util.List;
@@ -48,10 +52,17 @@
@MediumTest
public class CoordinatorLayoutTest extends BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
+ private Instrumentation mInstrumentation;
+
public CoordinatorLayoutTest() {
super(CoordinatorLayoutActivity.class);
}
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ }
+
@Test
@SdkSuppress(minSdkVersion = 21)
public void testSetFitSystemWindows() {
@@ -334,4 +345,51 @@
});
}
+ @Test
+ public void testDodgeInsetBeforeLayout() throws Throwable {
+ final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+ // Add a dummy view, which will be used to trigger a hierarchy change.
+ final View dummy = new View(col.getContext());
+
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ col.addView(dummy);
+ }
+ });
+
+ // Wait for a layout.
+ mInstrumentation.waitForIdleSync();
+
+ final View dodge = new View(col.getContext());
+ final CoordinatorLayout.LayoutParams lpDodge = col.generateDefaultLayoutParams();
+ lpDodge.dodgeInsetEdges = Gravity.BOTTOM;
+ lpDodge.setBehavior(new Behavior() {
+ @Override
+ public boolean getInsetDodgeRect(CoordinatorLayout parent, View child, Rect rect) {
+ // Any non-empty rect is fine here.
+ rect.set(0, 0, 10, 10);
+ return true;
+ }
+ });
+
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ col.addView(dodge, lpDodge);
+
+ // Ensure the new view is in the list of children.
+ int heightSpec = MeasureSpec.makeMeasureSpec(col.getHeight(), MeasureSpec.EXACTLY);
+ int widthSpec = MeasureSpec.makeMeasureSpec(col.getWidth(), MeasureSpec.EXACTLY);
+ col.measure(widthSpec, heightSpec);
+
+ // Force a hierarchy change.
+ col.removeView(dummy);
+ }
+ });
+
+ // Wait for a layout.
+ mInstrumentation.waitForIdleSync();
+ }
}
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 639e906..26a8444 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -42,6 +42,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -341,7 +342,11 @@
return;
}
int eventType = parser.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
+ final int innerDepth = parser.getDepth() + 1;
+
+ // Parse everything until the end of the animated-vector element.
+ while (eventType != XmlPullParser.END_DOCUMENT
+ && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
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 7dc7b9f..57c8c93 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -14,11 +14,7 @@
package android.support.graphics.drawable;
-import android.support.annotation.RestrictTo;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
import android.annotation.TargetApi;
import android.content.res.ColorStateList;
@@ -38,34 +34,190 @@
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
-import android.graphics.Region;
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.RestrictTo;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
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;
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
/**
* For API 24 and above, this class is delegating to the framework's {@link VectorDrawable}.
* For older API version, this class lets you create a drawable based on an XML vector graphic.
- * <p>
- * VectorDrawableCompat are defined in the same XML format as {@link VectorDrawable}.
- * </p>
+ * <p/>
* You can always create a VectorDrawableCompat object and use it as a Drawable by the Java API.
* In order to refer to VectorDrawableCompat inside a XML file, you can use app:srcCompat attribute
* in AppCompat library's ImageButton or ImageView.
+ * <p/>
+ * <strong>Note:</strong> To optimize for the re-drawing performance, one bitmap cache is created
+ * for each VectorDrawableCompat. Therefore, referring to the same VectorDrawableCompat means
+ * sharing the same bitmap cache. If these references don't agree upon on the same size, the bitmap
+ * will be recreated and redrawn every time size is changed. In other words, if a VectorDrawable is
+ * used for different sizes, it is more efficient to create multiple VectorDrawables, one for each
+ * size.
+ * <p/>
+ * VectorDrawableCompat can be defined in an XML file with the <code><vector></code> element.
+ * <p/>
+ * The VectorDrawableCompat 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>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : No.</dd>
+ * <dt><code>android:tintMode</code></dt>
+ * <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : No.</dd>
+ * <dt><code>android:alpha</code></dt>
+ * <dd>The opacity of this drawable.</dd>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : No.</dd>
+ * <dt><code>android:rotation</code></dt>
+ * <dd>The degrees of rotation of the group.</dd>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:scaleX</code></dt>
+ * <dd>The amount of scale on the X Coordinate.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:scaleY</code></dt>
+ * <dd>The amount of scale on the Y coordinate.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:translateX</code></dt>
+ * <dd>The amount of translation on the X coordinate.
+ * This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:translateY</code></dt>
+ * <dd>The amount of translation on the Y coordinate.
+ * This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : No.</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>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:fillColor</code></dt>
+ * <dd>Specifies the color used to fill the path.
+ * If this property is animated, any value set by the animation will override the original value.
+ * No path fill is drawn if this property is not specified.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:strokeColor</code></dt>
+ * <dd>Specifies the color used to draw the path outline.
+ * If this property is animated, any value set by the animation will override the original value.
+ * No path outline is drawn if this property is not specified.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:strokeWidth</code></dt>
+ * <dd>The width a path stroke.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:strokeAlpha</code></dt>
+ * <dd>The opacity of a path stroke.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:fillAlpha</code></dt>
+ * <dd>The opacity to fill the path with.</dd>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : Yes.</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>
+ * <dd>Animatable : Yes.</dd>
+ * <dt><code>android:strokeLineCap</code></dt>
+ * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
+ * <dd>Animatable : No.</dd>
+ * <dt><code>android:strokeLineJoin</code></dt>
+ * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
+ * <dd>Animatable : No.</dd>
+ * <dt><code>android:strokeMiterLimit</code></dt>
+ * <dd>Sets the Miter limit for a stroked path.</dd>
+ * <dd>Animatable : No.</dd>
+ * </dl></dd>
+ * </dl>
+ *
+ * <dl>
+ * <dt><code><clip-path></code></dt>
+ * <dd>Defines path to be the current clip. Note that the clip path only apply to
+ * the current group and its children.
+ * <dl>
+ * <dt><code>android:name</code></dt>
+ * <dd>Defines the name of the clip path.</dd>
+ * <dd>Animatable : No.</dd>
+ * <dt><code>android:pathData</code></dt>
+ * <dd>Defines clip path using the same format as "d" attribute
+ * in the SVG's path data.</dd>
+ * <dd>Animatable : Yes.</dd>
+ * </dl></dd>
+ * </dl>
*/
+
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class VectorDrawableCompat extends VectorDrawableCommon {
static final String LOGTAG = "VectorDrawableCompat";
@@ -585,7 +737,11 @@
groupStack.push(pathRenderer.mRootGroup);
int eventType = parser.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
+ final int innerDepth = parser.getDepth() + 1;
+
+ // Parse everything until the end of the vector element.
+ while (eventType != XmlPullParser.END_DOCUMENT
+ && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
final VGroup currentGroup = groupStack.peek();
diff --git a/transition/Android.mk b/transition/Android.mk
index a401d77..254b758 100644
--- a/transition/Android.mk
+++ b/transition/Android.mk
@@ -43,6 +43,7 @@
LOCAL_MODULE := android-support-transition-ics
LOCAL_SDK_VERSION := 14
LOCAL_SRC_FILES := $(call all-java-files-under, ics)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-base
LOCAL_JAVA_LIBRARIES := android-support-transition-res \
android-support-v4
@@ -53,6 +54,7 @@
LOCAL_MODULE := android-support-transition-kitkat
LOCAL_SDK_VERSION := 19
LOCAL_SRC_FILES := $(call all-java-files-under, kitkat)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-ics
LOCAL_JAVA_LIBRARIES := android-support-transition-res \
android-support-v4
@@ -63,6 +65,7 @@
LOCAL_MODULE := android-support-transition-api21
LOCAL_SDK_VERSION := 21
LOCAL_SRC_FILES := $(call all-java-files-under, api21)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-kitkat
LOCAL_JAVA_LIBRARIES := android-support-transition-res \
android-support-v4
@@ -73,6 +76,7 @@
LOCAL_MODULE := android-support-transition-api23
LOCAL_SDK_VERSION := 23
LOCAL_SRC_FILES := $(call all-java-files-under, api23)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-api21
LOCAL_JAVA_LIBRARIES := android-support-transition-res \
android-support-v4
@@ -86,6 +90,7 @@
LOCAL_MODULE := android-support-transition
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-api23
LOCAL_JAVA_LIBRARIES := android-support-transition-res \
android-support-v4
diff --git a/v17/leanback/res/values-bs-rBA/strings.xml b/v17/leanback/res/values-bs-rBA/strings.xml
index 63a76e2..cdfe434 100644
--- a/v17/leanback/res/values-bs-rBA/strings.xml
+++ b/v17/leanback/res/values-bs-rBA/strings.xml
@@ -53,5 +53,5 @@
<string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
<string name="lb_time_separator" msgid="2763247350845477227">":"</string>
<string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAPOČNITE"</string>
- <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Naprijed"</string>
+ <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Sljedeća"</string>
</resources>
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
index 4e25f71..a203252 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV9.java
@@ -304,6 +304,10 @@
@Override
public void onDestroy() {
+ if (mInvalidatePanelMenuPosted) {
+ mWindow.getDecorView().removeCallbacks(mInvalidatePanelMenuRunnable);
+ }
+
super.onDestroy();
if (mActionBar != null) {
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index 6f42ea9..b51df4b 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -89,11 +89,10 @@
private static void installDefaultInflateDelegates(@NonNull AppCompatDrawableManager manager) {
final int sdk = Build.VERSION.SDK_INT;
// This sdk version check will affect src:appCompat code path.
+ // Although VectorDrawable exists in Android framework from Lollipop, AppCompat will use the
+ // VectorDrawableCompat before Nougat to utilize the bug fixes in VectorDrawableCompat.
if (sdk < 24) {
- // We only want to use the automatic VectorDrawableCompat handling where it's
- // needed: on devices running before Lollipop
manager.addDelegate("vector", new VdcInflateDelegate());
-
if (sdk >= 11) {
// AnimatedVectorDrawableCompat only works on API v11+
manager.addDelegate("animated-vector", new AvdcInflateDelegate());
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index 95c6ac2..ab27c9e 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -2821,6 +2821,11 @@
final Object obj = msg.obj;
final int arg = msg.arg1;
+ if (what == MSG_ROUTE_CHANGED
+ && getSelectedRoute().getId().equals(((RouteInfo) obj).getId())) {
+ updateSelectedRouteIfNeeded(true);
+ }
+
// Synchronize state with the system media router.
syncWithSystemProvider(what, obj);
diff --git a/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java b/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
index 6a2451b..a31eb6f 100644
--- a/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
+++ b/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
@@ -296,7 +296,6 @@
if (mRouteTypes != newRouteTypes || mActiveScan != newActiveScan) {
mRouteTypes = newRouteTypes;
mActiveScan = newActiveScan;
- updateCallback();
updateSystemRoutes();
}
}
@@ -309,6 +308,7 @@
}
private void updateSystemRoutes() {
+ updateCallback();
boolean changed = false;
for (Object routeObj : MediaRouterJellybean.getRoutes(mRouterObj)) {
changed |= addSystemRouteNoPublish(routeObj);
diff --git a/v7/recyclerview/src/android/support/v7/widget/SnapHelper.java b/v7/recyclerview/src/android/support/v7/widget/SnapHelper.java
index 915556e..37197e4 100644
--- a/v7/recyclerview/src/android/support/v7/widget/SnapHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/SnapHelper.java
@@ -53,6 +53,7 @@
}
}
+ @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dx != 0 || dy != 0) {
mScrolled = true;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
index 3a72152..9109c87 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
@@ -16,6 +16,7 @@
package android.support.v7.widget;
import android.content.Context;
+import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
@@ -152,6 +153,8 @@
CountDownLatch prefetchLatch;
+ OrientationHelper mSecondaryOrientation;
+
List<GridLayoutManagerTest.Callback>
mCallbacks = new ArrayList<GridLayoutManagerTest.Callback>();
@@ -182,6 +185,26 @@
}
@Override
+ public void setOrientation(int orientation) {
+ super.setOrientation(orientation);
+ mSecondaryOrientation = null;
+ }
+
+ @Override
+ void ensureLayoutState() {
+ super.ensureLayoutState();
+ if (mSecondaryOrientation == null) {
+ if (getOrientation() == RecyclerView.HORIZONTAL) {
+ mSecondaryOrientation = OrientationHelper.createOrientationHelper(this,
+ RecyclerView.VERTICAL);
+ } else {
+ mSecondaryOrientation = OrientationHelper.createOrientationHelper(this,
+ RecyclerView.HORIZONTAL);
+ }
+ }
+ }
+
+ @Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
for (GridLayoutManagerTest.Callback callback : mCallbacks) {
@@ -213,6 +236,23 @@
};
}
+ Rect getViewBounds(View view) {
+ if (getOrientation() == HORIZONTAL) {
+ return new Rect(
+ mOrientationHelper.getDecoratedStart(view),
+ mSecondaryOrientation.getDecoratedStart(view),
+ mOrientationHelper.getDecoratedEnd(view),
+ mSecondaryOrientation.getDecoratedEnd(view));
+ } else {
+ return new Rect(
+ mSecondaryOrientation.getDecoratedStart(view),
+ mOrientationHelper.getDecoratedStart(view),
+ mSecondaryOrientation.getDecoratedEnd(view),
+ mOrientationHelper.getDecoratedEnd(view));
+ }
+
+ }
+
public void expectLayout(int layoutCount) {
mLayoutLatch = new CountDownLatch(layoutCount);
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
index 50c9ba3..54190f1 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
@@ -21,12 +21,14 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static java.util.concurrent.TimeUnit.SECONDS;
import android.content.Context;
import android.graphics.Rect;
+import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.util.Log;
import android.view.View;
@@ -83,14 +85,21 @@
}
void setupByConfig(Config config, boolean waitForFirstLayout) throws Throwable {
+ setupByConfig(config, waitForFirstLayout, null, null);
+ }
+
+ void setupByConfig(Config config, boolean waitForFirstLayout,
+ @Nullable RecyclerView.LayoutParams childLayoutParams,
+ @Nullable RecyclerView.LayoutParams parentLayoutParams) throws Throwable {
mRecyclerView = inflateWrappedRV();
mRecyclerView.setHasFixedSize(true);
- mTestAdapter = config.mTestAdapter == null ? new TestAdapter(config.mItemCount)
+ mTestAdapter = config.mTestAdapter == null
+ ? new TestAdapter(config.mItemCount, childLayoutParams)
: config.mTestAdapter;
mRecyclerView.setAdapter(mTestAdapter);
mLayoutManager = new WrappedLinearLayoutManager(getActivity(), config.mOrientation,
- config.mReverseLayout);
+ config.mReverseLayout);
mLayoutManager.setStackFromEnd(config.mStackFromEnd);
mLayoutManager.setRecycleChildrenOnDetach(config.mRecycleChildrenOnDetach);
mRecyclerView.setLayoutManager(mLayoutManager);
@@ -102,6 +111,10 @@
)
);
}
+ if (parentLayoutParams != null) {
+ mRecyclerView.setLayoutParams(parentLayoutParams);
+ }
+
if (waitForFirstLayout) {
waitForFirstLayout();
}
@@ -342,15 +355,26 @@
class WrappedLinearLayoutManager extends LinearLayoutManager {
CountDownLatch layoutLatch;
-
CountDownLatch snapLatch;
-
CountDownLatch prefetchLatch;
+ CountDownLatch callbackLatch;
OrientationHelper mSecondaryOrientation;
OnLayoutListener mOnLayoutListener;
+ RecyclerView.OnScrollListener mCallbackListener = new RecyclerView.OnScrollListener() {
+
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ super.onScrollStateChanged(recyclerView, newState);
+ callbackLatch.countDown();
+ if (callbackLatch.getCount() == 0L) {
+ removeOnScrollListener(this);
+ }
+ }
+ };
+
public WrappedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@@ -359,6 +383,15 @@
layoutLatch = new CountDownLatch(count);
}
+ public void expectCallbacks(int count) throws Throwable {
+ callbackLatch = new CountDownLatch(count);
+ mRecyclerView.addOnScrollListener(mCallbackListener);
+ }
+
+ private void removeOnScrollListener(RecyclerView.OnScrollListener listener) {
+ mRecyclerView.removeOnScrollListener(listener);
+ }
+
public void waitForLayout(int seconds) throws Throwable {
layoutLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
checkForMainThreadException();
@@ -372,6 +405,13 @@
});
}
+ public void assertNoCallbacks(String msg, long timeout) throws Throwable {
+ callbackLatch.await(timeout, TimeUnit.SECONDS);
+ long latchCount = callbackLatch.getCount();
+ assertFalse(msg + " :" + latchCount, latchCount == 0);
+ removeOnScrollListener(mCallbackListener);
+ }
+
public void expectPrefetch(int count) {
prefetchLatch = new CountDownLatch(count);
}
@@ -413,8 +453,7 @@
// use a runnable to ensure RV layout is finished
getInstrumentation().runOnMainSync(new Runnable() {
@Override
- public void run() {
- }
+ public void run() {}
});
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 7a7a4d4..0373251 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -27,6 +27,7 @@
import android.app.Instrumentation;
import android.graphics.Rect;
import android.os.Looper;
+import android.support.annotation.Nullable;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.v4.view.ViewCompat;
@@ -791,10 +792,16 @@
ViewAttachDetachCounter mAttachmentCounter = new ViewAttachDetachCounter();
List<Item> mItems;
+ final @Nullable RecyclerView.LayoutParams mLayoutParams;
public TestAdapter(int count) {
+ this(count, null);
+ }
+
+ public TestAdapter(int count, @Nullable RecyclerView.LayoutParams layoutParams) {
mItems = new ArrayList<Item>(count);
addItems(0, count, DEFAULT_ITEM_PREFIX);
+ mLayoutParams = layoutParams;
}
private void addItems(int pos, int count, String prefix) {
@@ -848,6 +855,9 @@
final Item item = mItems.get(position);
((TextView) (holder.itemView)).setText(item.mText + "(" + item.mId + ")");
holder.mBoundItem = item;
+ if (mLayoutParams != null) {
+ holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(mLayoutParams));
+ }
}
public Item getItemAt(int position) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
index 0ba8fed..6dc80bd 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
@@ -168,7 +168,11 @@
mGlm.waitForLayout(2);
View view = findCenterView(mGlm);
- int scrollDistance = (getViewDimension(view) / 2) + 10;
+ int scrollDistance = distFromCenter(view) / 2;
+ if (scrollDistance == 0) {
+ return;
+ }
+
int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
mGlm.expectIdleState(2);
@@ -208,6 +212,14 @@
}
}
+ private int distFromCenter(View view) {
+ if (mGlm.canScrollHorizontally()) {
+ return Math.abs(mRecyclerView.getWidth() / 2 - mGlm.getViewBounds(view).centerX());
+ } else {
+ return Math.abs(mRecyclerView.getHeight() / 2 - mGlm.getViewBounds(view).centerY());
+ }
+ }
+
private boolean fling(final int velocityX, final int velocityY)
throws Throwable {
final AtomicBoolean didStart = new AtomicBoolean(false);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
index ae19fc1..3d978da 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
@@ -59,6 +59,32 @@
@MediumTest
@Test
+ public void snapOnScrollSameViewEdge() throws Throwable {
+ final Config config = (Config) mConfig.clone();
+ // Ensure that the views are big enough to reach the pathological case when the view closest
+ // to the center is an edge view, but it cannot scroll further in order to snap.
+ setupByConfig(config, true, new RecyclerView.LayoutParams(1000, 1000),
+ new RecyclerView.LayoutParams(1500, 1500));
+ SnapHelper snapHelper = new LinearSnapHelper();
+ mLayoutManager.expectIdleState(1);
+ snapHelper.attachToRecyclerView(mRecyclerView);
+ mLayoutManager.waitForSnap(10);
+
+ // Record the current center view.
+ View view = findCenterView(mLayoutManager);
+
+ int scrollDistance = (getViewDimension(view) / 2) - 1;
+ int scrollDist = config.mStackFromEnd == config.mReverseLayout
+ ? -scrollDistance : scrollDistance;
+ mLayoutManager.expectIdleState(1);
+ smoothScrollBy(scrollDist);
+ mLayoutManager.waitForSnap(10);
+ mLayoutManager.expectCallbacks(5);
+ mLayoutManager.assertNoCallbacks("There should be no callbacks after some time", 3);
+ }
+
+ @MediumTest
+ @Test
public void snapOnScrollSameView() throws Throwable {
final Config config = (Config) mConfig.clone();
setupByConfig(config, true);
@@ -76,7 +102,7 @@
// Views have not changed
View viewAfterFling = findCenterView(mLayoutManager);
- assertSame("The view should have scrolled", view, viewAfterFling);
+ assertSame("The view should NOT have scrolled", view, viewAfterFling);
assertCenterAligned(viewAfterFling);
}
@@ -165,7 +191,11 @@
mLayoutManager.waitForLayout(2);
View view = findCenterView(mLayoutManager);
- int scrollDistance = (getViewDimension(view) / 2) + 10;
+ int scrollDistance = distFromCenter(view) / 2;
+ if (scrollDistance == 0) {
+ return;
+ }
+
int scrollDist = mReverseScroll ? -scrollDistance : scrollDistance;
mLayoutManager.expectIdleState(2);
@@ -201,6 +231,16 @@
}
}
+ private int distFromCenter(View view) {
+ if (mLayoutManager.canScrollHorizontally()) {
+ return Math.abs(mRecyclerView.getWidth() / 2 -
+ mLayoutManager.getViewBounds(view).centerX());
+ } else {
+ return Math.abs(mRecyclerView.getHeight() / 2 -
+ mLayoutManager.getViewBounds(view).centerY());
+ }
+ }
+
private boolean fling(final int velocityX, final int velocityY) throws Throwable {
final AtomicBoolean didStart = new AtomicBoolean(false);
runTestOnUiThread(new Runnable() {