summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Pasanen <dan.pasanen@gmail.com>2017-04-05 07:25:03 -0500
committerDan Pasanen <dan.pasanen@gmail.com>2017-04-05 07:25:03 -0500
commit5a832ea51874a2381564c5329bf47db518d47ff7 (patch)
tree1a4ee240e75a30745466481244da51e415704136
parent0285afecf474df8254879e2c35043d4174713d69 (diff)
parent9201a902d80346b09042da74bf3639f61622e285 (diff)
downloadandroid_frameworks_support-cm-14.1.tar.gz
android_frameworks_support-cm-14.1.tar.bz2
android_frameworks_support-cm-14.1.zip
Merge tag 'android-7.1.2_r2' into cm-14.1staging/cm-14.1_android-7.1.2_r2cm-14.1
Android 7.1.2 Release 2 (N2G47E) # gpg: Signature made Mon 03 Apr 2017 01:41:48 AM CDT # gpg: using DSA key E8AD3F819AB10E78 # gpg: Can't check signature: No public key
-rw-r--r--build.gradle4
-rw-r--r--compat/gingerbread/android/support/v4/os/BuildCompat.java6
-rw-r--r--compat/java/android/support/v4/widget/TextViewCompat.java5
-rw-r--r--compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java13
-rw-r--r--compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java4
-rw-r--r--design/res/values/attrs.xml1
-rw-r--r--design/res/values/colors.xml2
-rw-r--r--design/res/values/dimens.xml2
-rw-r--r--design/res/values/styles.xml1
-rw-r--r--design/src/android/support/design/internal/BottomNavigationItemView.java6
-rw-r--r--design/src/android/support/design/internal/BottomNavigationMenu.java13
-rw-r--r--design/src/android/support/design/internal/BottomNavigationMenuView.java38
-rw-r--r--design/src/android/support/design/widget/BottomNavigationView.java34
-rw-r--r--design/src/android/support/design/widget/CoordinatorLayout.java54
-rw-r--r--design/src/android/support/design/widget/TextInputEditText.java11
-rw-r--r--design/src/android/support/design/widget/TextInputLayout.java26
-rw-r--r--design/tests/src/android/support/design/widget/BottomNavigationViewTest.java38
-rw-r--r--design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java90
-rwxr-xr-xdesign/tests/src/android/support/design/widget/TextInputLayoutTest.java84
-rw-r--r--graphics/drawable/animated/build.gradle4
-rw-r--r--graphics/drawable/animated/proguard-rules.pro19
-rw-r--r--graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java82
-rw-r--r--graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java2
-rw-r--r--graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java76
-rw-r--r--media-compat/java/android/support/v4/media/MediaBrowserCompat.java4
-rw-r--r--samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml18
-rw-r--r--samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml11
-rw-r--r--samples/SupportDesignDemos/res/values/strings.xml1
-rw-r--r--samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java14
-rw-r--r--v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java2
-rw-r--r--v17/leanback/res/layout/lb_guidedstep_fragment.xml7
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java2
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java11
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java11
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java3
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java31
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java47
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java36
-rw-r--r--v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java36
-rw-r--r--v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java7
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java5
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java36
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java34
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java16
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java7
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java1
-rw-r--r--v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java5
-rw-r--r--v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java28
-rw-r--r--v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java28
-rw-r--r--v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java30
-rw-r--r--v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java30
-rw-r--r--v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java157
-rw-r--r--v7/appcompat/res/values-es-rUS/strings.xml2
-rw-r--r--v7/appcompat/res/values-hy-rAM/strings.xml2
-rw-r--r--v7/appcompat/res/values-kn-rIN/strings.xml4
-rw-r--r--v7/appcompat/res/values-v11/themes_base.xml25
-rw-r--r--v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java15
-rw-r--r--v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java24
-rw-r--r--v7/appcompat/tests/res/layout/appcompat_button_activity.xml7
-rw-r--r--v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java33
-rw-r--r--v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java18
-rw-r--r--v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java154
-rw-r--r--v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java21
-rw-r--r--v7/mediarouter/res/values-b+sr+Latn/strings.xml2
-rw-r--r--v7/mediarouter/res/values-gl-rES/strings.xml2
-rw-r--r--v7/mediarouter/res/values-hi/strings.xml4
-rw-r--r--v7/mediarouter/res/values-pa-rIN/strings.xml2
-rw-r--r--v7/mediarouter/res/values-sr/strings.xml2
-rw-r--r--v7/mediarouter/res/values-zh-rCN/strings.xml2
-rw-r--r--v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java5
-rw-r--r--v7/recyclerview/src/android/support/v7/widget/RecyclerView.java14
-rw-r--r--v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java52
-rw-r--r--v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java6
-rw-r--r--v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java58
74 files changed, 1288 insertions, 399 deletions
diff --git a/build.gradle b/build.gradle
index 258d4d011e..952f18706f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,8 +30,8 @@ dependencies {
doclava project(':doclava')
}
-ext.supportVersion = '25.0.0'
-ext.extraVersion = 39
+ext.supportVersion = '25.0.1'
+ext.extraVersion = 40
ext.supportRepoOut = ''
ext.buildToolsVersion = '23.0.2'
ext.buildNumber = Integer.toString(ext.extraVersion)
diff --git a/compat/gingerbread/android/support/v4/os/BuildCompat.java b/compat/gingerbread/android/support/v4/os/BuildCompat.java
index 3c73e4dc43..a49b5aa447 100644
--- a/compat/gingerbread/android/support/v4/os/BuildCompat.java
+++ b/compat/gingerbread/android/support/v4/os/BuildCompat.java
@@ -27,6 +27,12 @@ import android.text.TextUtils;
public class BuildCompat {
private BuildCompat() {
}
+ /* Boilerplate for isAtLeast${PLATFORM}:
+ * public static boolean isAtLeast*() {
+ * return !"REL".equals(VERSION.CODENAME)
+ * && ("${PLATFORM}".equals(VERSION.CODENAME) || VERSION.CODENAME.startsWith("${PLATFORM}MR"));
+ * }
+ */
/**
* Check if the device is running on the Android N release or newer.
diff --git a/compat/java/android/support/v4/widget/TextViewCompat.java b/compat/java/android/support/v4/widget/TextViewCompat.java
index 6c96ef3123..faa252ae19 100644
--- a/compat/java/android/support/v4/widget/TextViewCompat.java
+++ b/compat/java/android/support/v4/widget/TextViewCompat.java
@@ -158,6 +158,11 @@ public final class TextViewCompat {
TextViewCompatJbMr2.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
start, top, end, bottom);
}
+
+ @Override
+ public Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
+ return TextViewCompatJbMr2.getCompoundDrawablesRelative(textView);
+ }
}
static class Api23TextViewCompatImpl extends JbMr2TextViewCompatImpl {
diff --git a/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java b/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java
index fc088ed1af..fa473cf6d8 100644
--- a/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java
+++ b/compat/jellybean-mr1/android/support/v4/widget/TextViewCompatJbMr1.java
@@ -46,8 +46,17 @@ class TextViewCompatJbMr1 {
bottom);
}
- static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
- return textView.getCompoundDrawablesRelative();
+ public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
+ final boolean rtl = textView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ final Drawable[] compounds = textView.getCompoundDrawables();
+ if (rtl) {
+ // If we're on RTL, we need to invert the horizontal result like above
+ final Drawable start = compounds[2];
+ final Drawable end = compounds[0];
+ compounds[0] = start;
+ compounds[2] = end;
+ }
+ return compounds;
}
}
diff --git a/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java b/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
index 73f9666f9e..03b1e153d0 100644
--- a/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
+++ b/compat/jellybean-mr2/android/support/v4/widget/TextViewCompatJbMr2.java
@@ -42,4 +42,8 @@ class TextViewCompatJbMr2 {
textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
+ public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
+ return textView.getCompoundDrawablesRelative();
+ }
+
}
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 545a82ea06..41e0c0f0ae 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -469,6 +469,7 @@
<attr name="itemIconTint"/>
<attr name="itemTextColor"/>
<attr name="itemBackground"/>
+ <attr name="elevation"/>
</declare-styleable>
</resources>
diff --git a/design/res/values/colors.xml b/design/res/values/colors.xml
index ebf6412356..eb18f05a17 100644
--- a/design/res/values/colors.xml
+++ b/design/res/values/colors.xml
@@ -38,4 +38,6 @@
<color name="design_snackbar_background_color">#323232</color>
+ <color name="design_bottom_navigation_shadow_color">#14000000</color>
+
</resources> \ No newline at end of file
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
index 63e98b876d..de715ce8a5 100644
--- a/design/res/values/dimens.xml
+++ b/design/res/values/dimens.xml
@@ -59,6 +59,8 @@
<dimen name="design_bottom_sheet_peek_height_min">64dp</dimen>
<dimen name="design_bottom_navigation_height">56dp</dimen>
+ <dimen name="design_bottom_navigation_elevation">8dp</dimen>
+ <dimen name="design_bottom_navigation_shadow_height">1dp</dimen>
<dimen name="design_bottom_navigation_text_size">12sp</dimen>
<dimen name="design_bottom_navigation_active_text_size">14sp</dimen>
<dimen name="design_bottom_navigation_margin">8dp</dimen>
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
index c8b9cd584a..820742fa79 100644
--- a/design/res/values/styles.xml
+++ b/design/res/values/styles.xml
@@ -44,6 +44,7 @@
<style name="Widget.Design.BottomNavigationView" parent="">
<item name="itemBackground">?attr/selectableItemBackgroundBorderless</item>
+ <item name="elevation">@dimen/design_bottom_navigation_elevation</item>
</style>
<style name="Base.Widget.Design.TabLayout" parent="android:Widget">
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
index ea22399f0a..5403ba12be 100644
--- a/design/src/android/support/design/internal/BottomNavigationItemView.java
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -16,6 +16,8 @@
package android.support.design.internal;
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -35,8 +37,6 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
/**
* @hide
*/
@@ -131,8 +131,6 @@ public class BottomNavigationItemView extends FrameLayout implements MenuView.It
@Override
public void setChecked(boolean checked) {
- mItemData.setChecked(checked);
-
ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);
ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());
ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);
diff --git a/design/src/android/support/design/internal/BottomNavigationMenu.java b/design/src/android/support/design/internal/BottomNavigationMenu.java
index 883209775e..9862175b25 100644
--- a/design/src/android/support/design/internal/BottomNavigationMenu.java
+++ b/design/src/android/support/design/internal/BottomNavigationMenu.java
@@ -16,14 +16,15 @@
package android.support.design.internal;
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
import android.content.Context;
import android.support.annotation.RestrictTo;
import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuItemImpl;
import android.view.MenuItem;
import android.view.SubMenu;
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
/**
* @hide
*/
@@ -47,6 +48,12 @@ public final class BottomNavigationMenu extends MenuBuilder {
"Maximum number of items supported by BottomNavigationView is " + MAX_ITEM_COUNT
+ ". Limit can be checked with BottomNavigationView#getMaxItemCount()");
}
- return super.addInternal(group, id, categoryOrder, title);
+ stopDispatchingItemsChanged();
+ final MenuItem item = super.addInternal(group, id, categoryOrder, title);
+ if (item instanceof MenuItemImpl) {
+ ((MenuItemImpl) item).setExclusiveCheckable(true);
+ }
+ startDispatchingItemsChanged();
+ return item;
}
}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
index 096bdd83aa..ba43b5bf7a 100644
--- a/design/src/android/support/design/internal/BottomNavigationMenuView.java
+++ b/design/src/android/support/design/internal/BottomNavigationMenuView.java
@@ -97,10 +97,6 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
@Override
public void initialize(MenuBuilder menu) {
mMenu = menu;
- if (mMenu == null) return;
- if (mMenu.size() > mActiveButton) {
- mMenu.getItem(mActiveButton).setChecked(true);
- }
}
@Override
@@ -125,7 +121,7 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
}
}
} else {
- final int maxAvailable = width / count;
+ final int maxAvailable = width / (count == 0 ? 1 : count);
final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth);
int extra = width - childWidth * count;
for (int i = 0; i < count; i++) {
@@ -181,9 +177,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
}
/**
- * Set the tint which is applied to the menu items' icons.
+ * Sets the tint which is applied to the menu items' icons.
*
- * @param tint the tint to apply.
+ * @param tint the tint to apply
*/
public void setIconTintList(ColorStateList tint) {
mItemIconTint = tint;
@@ -196,7 +192,7 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
/**
* Returns the tint which is applied to menu items' icons.
*
- * @return The ColorStateList that is used to tint menu items' icons.
+ * @return the ColorStateList that is used to tint menu items' icons
*/
@Nullable
public ColorStateList getIconTintList() {
@@ -204,7 +200,7 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
}
/**
- * Set the text color to be used on menu items.
+ * Sets the text color to be used on menu items.
*
* @param color the ColorStateList used for menu items' text.
*/
@@ -219,15 +215,16 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
/**
* Returns the text color used on menu items.
*
- * @return the ColorStateList used for menu items' text.
+ * @return the ColorStateList used for menu items' text
*/
public ColorStateList getItemTextColor() {
return mItemTextColor;
}
/**
- * Sets the resource id to be used for item background.
- * @param background the resource id of the background.
+ * Sets the resource ID to be used for item background.
+ *
+ * @param background the resource ID of the background
*/
public void setItemBackgroundRes(int background) {
mItemBackgroundRes = background;
@@ -238,9 +235,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
}
/**
- * Returns the background resource of the menu items.
+ * Returns the resource ID for the background of the menu items.
*
- * @return the resource id of the background.
+ * @return the resource ID for the background
*/
public int getItemBackgroundRes() {
return mItemBackgroundRes;
@@ -257,6 +254,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
}
}
removeAllViews();
+ if (mMenu.size() == 0) {
+ return;
+ }
mButtons = new BottomNavigationItemView[mMenu.size()];
mShiftingMode = mMenu.size() > 3;
for (int i = 0; i < mMenu.size(); i++) {
@@ -274,6 +274,8 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
child.setOnClickListener(mOnClickListener);
addView(child);
}
+ mActiveButton = Math.min(mMenu.size() - 1, mActiveButton);
+ mMenu.getItem(mActiveButton).setChecked(true);
}
public void updateMenuView() {
@@ -285,6 +287,9 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
}
for (int i = 0; i < menuSize; i++) {
mPresenter.setUpdateSuspended(true);
+ if (mMenu.getItem(i).isChecked()) {
+ mActiveButton = i;
+ }
mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0);
mPresenter.setUpdateSuspended(false);
}
@@ -295,10 +300,7 @@ public class BottomNavigationMenuView extends ViewGroup implements MenuView {
mAnimationHelper.beginDelayedTransition(this);
- mPresenter.setUpdateSuspended(true);
- mButtons[mActiveButton].setChecked(false);
- mButtons[newButton].setChecked(true);
- mPresenter.setUpdateSuspended(false);
+ mMenu.getItem(newButton).setChecked(true);
mActiveButton = newButton;
}
diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java
index 8a8e0bd052..e3a81b3f77 100644
--- a/design/src/android/support/design/widget/BottomNavigationView.java
+++ b/design/src/android/support/design/widget/BottomNavigationView.java
@@ -18,6 +18,7 @@ package android.support.design.widget;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.os.Build;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -25,6 +26,8 @@ import android.support.design.R;
import android.support.design.internal.BottomNavigationMenu;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.internal.BottomNavigationPresenter;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
import android.support.v7.content.res.AppCompatResources;
import android.support.v7.view.SupportMenuInflater;
import android.support.v7.view.menu.MenuBuilder;
@@ -35,6 +38,7 @@ import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -117,7 +121,7 @@ public class BottomNavigationView extends FrameLayout {
mPresenter.setBottomNavigationMenuView(mMenuView);
mMenuView.setPresenter(mPresenter);
mMenu.addMenuPresenter(mPresenter);
-
+ mPresenter.initForMenu(getContext(), mMenu);
// Custom attributes
TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
@@ -138,6 +142,10 @@ public class BottomNavigationView extends FrameLayout {
mMenuView.setItemTextColor(
createDefaultColorStateList(android.R.attr.textColorSecondary));
}
+ if (a.hasValue(R.styleable.BottomNavigationView_elevation)) {
+ ViewCompat.setElevation(this, a.getDimensionPixelSize(
+ R.styleable.BottomNavigationView_elevation, 0));
+ }
int itemBackground = a.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
mMenuView.setItemBackgroundRes(itemBackground);
@@ -148,6 +156,9 @@ public class BottomNavigationView extends FrameLayout {
a.recycle();
addView(mMenuView, params);
+ if (Build.VERSION.SDK_INT < 21) {
+ addCompatibilityTopDivider(context);
+ }
mMenu.setCallback(new MenuBuilder.Callback() {
@Override
@@ -188,7 +199,6 @@ public class BottomNavigationView extends FrameLayout {
public void inflateMenu(int resId) {
mPresenter.setUpdateSuspended(true);
getMenuInflater().inflate(resId, mMenu);
- mPresenter.initForMenu(getContext(), mMenu);
mPresenter.setUpdateSuspended(false);
mPresenter.updateMenuView(true);
}
@@ -224,10 +234,13 @@ public class BottomNavigationView extends FrameLayout {
}
/**
- * Returns the text color used on menu items.
+ * Returns colors used for the different states (normal, selected, focused, etc.) of the menu
+ * item text.
*
* @see #setItemTextColor(ColorStateList)
*
+ * @return the ColorStateList of colors used for the different states of the menu items text.
+ *
* @attr ref R.styleable#BottomNavigationView_itemTextColor
*/
@Nullable
@@ -236,7 +249,8 @@ public class BottomNavigationView extends FrameLayout {
}
/**
- * Set the text color to be used on menu items.
+ * Set the colors to use for the different states (normal, selected, focused, etc.) of the menu
+ * item text.
*
* @see #getItemTextColor()
*
@@ -286,6 +300,18 @@ public class BottomNavigationView extends FrameLayout {
boolean onNavigationItemSelected(@NonNull MenuItem item);
}
+ private void addCompatibilityTopDivider(Context context) {
+ View divider = new View(context);
+ divider.setBackgroundColor(
+ ContextCompat.getColor(context, R.color.design_bottom_navigation_shadow_color));
+ FrameLayout.LayoutParams dividerParams = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ getResources().getDimensionPixelSize(
+ R.dimen.design_bottom_navigation_shadow_height));
+ divider.setLayoutParams(dividerParams);
+ addView(divider);
+ }
+
private MenuInflater getMenuInflater() {
if (mMenuInflater == null) {
mMenuInflater = new SupportMenuInflater(getContext());
diff --git a/design/src/android/support/design/widget/CoordinatorLayout.java b/design/src/android/support/design/widget/CoordinatorLayout.java
index 95669341cd..249aad2a99 100644
--- a/design/src/android/support/design/widget/CoordinatorLayout.java
+++ b/design/src/android/support/design/widget/CoordinatorLayout.java
@@ -155,6 +155,7 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
private final Rect mTempRect2 = new Rect();
private final Rect mTempRect3 = new Rect();
private final Rect mTempRect4 = new Rect();
+ private final Rect mTempRect5 = new Rect();
private final int[] mTempIntPair = new int[2];
private Paint mScrimPaint;
@@ -731,6 +732,11 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
final int childCount = mDependencySortedChildren.size();
for (int i = 0; i < childCount; i++) {
final View child = mDependencySortedChildren.get(i);
+ if (child.getVisibility() == GONE) {
+ // If the child is GONE, skip...
+ continue;
+ }
+
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
int keylineWidthUsed = 0;
@@ -843,6 +849,11 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
final int childCount = mDependencySortedChildren.size();
for (int i = 0; i < childCount; i++) {
final View child = mDependencySortedChildren.get(i);
+ if (child.getVisibility() == GONE) {
+ // If the child is GONE, skip...
+ continue;
+ }
+
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Behavior behavior = lp.getBehavior();
@@ -1310,42 +1321,51 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
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.
+ // 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);
+ final Rect bounds = mTempRect5;
+ bounds.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
+ if (bounds.isEmpty()) {
+ // Bounds are empty so there is nothing to dodge against, skip...
+ return;
+ }
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final Behavior behavior = lp.getBehavior();
- final Rect rect = mTempRect3;
- if (behavior != null && behavior.getInsetDodgeRect(this, child, rect)) {
- // Make sure that it intersects the views bounds
- if (!rect.intersect(child.getLeft(), child.getTop(),
- child.getRight(), child.getBottom())) {
- throw new IllegalArgumentException("Rect should intersect with child's bounds.");
+ final Rect dodgeRect = mTempRect3;
+ dodgeRect.setEmpty();
+
+ if (behavior != null && behavior.getInsetDodgeRect(this, child, dodgeRect)) {
+ // Make sure that the rect is within the view's bounds
+ if (!bounds.contains(dodgeRect)) {
+ throw new IllegalArgumentException("Rect should be within the child's bounds."
+ + " Rect:" + dodgeRect.toShortString()
+ + " | Bounds:" + bounds.toShortString());
}
} else {
- rect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
+ dodgeRect.set(bounds);
}
- if (rect.isEmpty()) {
+ if (dodgeRect.isEmpty()) {
// Rect is empty so there is nothing to dodge against, skip...
return;
}
+ final int absDodgeInsetEdges = GravityCompat.getAbsoluteGravity(lp.dodgeInsetEdges,
+ layoutDirection);
+
boolean offsetY = false;
if ((absDodgeInsetEdges & Gravity.TOP) == Gravity.TOP) {
- int distance = rect.top - lp.topMargin - lp.mInsetOffsetY;
+ int distance = dodgeRect.top - lp.topMargin - lp.mInsetOffsetY;
if (distance < inset.top) {
setInsetOffsetY(child, inset.top - distance);
offsetY = true;
}
}
if ((absDodgeInsetEdges & Gravity.BOTTOM) == Gravity.BOTTOM) {
- int distance = getHeight() - rect.bottom - lp.bottomMargin + lp.mInsetOffsetY;
+ int distance = getHeight() - dodgeRect.bottom - lp.bottomMargin + lp.mInsetOffsetY;
if (distance < inset.bottom) {
setInsetOffsetY(child, distance - inset.bottom);
offsetY = true;
@@ -1357,14 +1377,14 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
boolean offsetX = false;
if ((absDodgeInsetEdges & Gravity.LEFT) == Gravity.LEFT) {
- int distance = rect.left - lp.leftMargin - lp.mInsetOffsetX;
+ int distance = dodgeRect.left - lp.leftMargin - lp.mInsetOffsetX;
if (distance < inset.left) {
setInsetOffsetX(child, inset.left - distance);
offsetX = true;
}
}
if ((absDodgeInsetEdges & Gravity.RIGHT) == Gravity.RIGHT) {
- int distance = getWidth() - rect.right - lp.rightMargin + lp.mInsetOffsetX;
+ int distance = getWidth() - dodgeRect.right - lp.rightMargin + lp.mInsetOffsetX;
if (distance < inset.right) {
setInsetOffsetX(child, distance - inset.right);
offsetX = true;
diff --git a/design/src/android/support/design/widget/TextInputEditText.java b/design/src/android/support/design/widget/TextInputEditText.java
index a14143936e..7235ec220d 100644
--- a/design/src/android/support/design/widget/TextInputEditText.java
+++ b/design/src/android/support/design/widget/TextInputEditText.java
@@ -19,6 +19,7 @@ package android.support.design.widget;
import android.content.Context;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
+import android.view.View;
import android.view.ViewParent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -49,9 +50,13 @@ public class TextInputEditText extends AppCompatEditText {
if (ic != null && outAttrs.hintText == null) {
// If we don't have a hint and our parent is a TextInputLayout, use it's hint for the
// EditorInfo. This allows us to display a hint in 'extract mode'.
- final ViewParent parent = getParent();
- if (parent instanceof TextInputLayout) {
- outAttrs.hintText = ((TextInputLayout) parent).getHint();
+ ViewParent parent = getParent();
+ while (parent instanceof View) {
+ if (parent instanceof TextInputLayout) {
+ outAttrs.hintText = ((TextInputLayout) parent).getHint();
+ break;
+ }
+ parent = parent.getParent();
}
}
return ic;
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 33559565e4..e645a34255 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -77,6 +77,16 @@ import android.widget.TextView;
* {@link #setError(CharSequence)}, and a character counter via
* {@link #setCounterEnabled(boolean)}.</p>
*
+ * <p>Password visibility toggling is also supported via the
+ * {@link #setPasswordVisibilityToggleEnabled(boolean)} API and related attribute.
+ * If enabled, a button is displayed to toggle between the password being displayed as plain-text
+ * or disguised, when your EditText is set to display a password.</p>
+ *
+ * <p><strong>Note:</strong> When using the password toggle functionality, the 'end' compound
+ * drawable of the EditText will be overridden while the toggle is enabled. To ensure that any
+ * existing drawables are restored correctly, you should set those compound drawables relatively
+ * (start/end), opposed to absolutely (left/right).</p>
+ *
* The {@link TextInputEditText} class is provided to be used as a child of this layout. Using
* TextInputEditText allows TextInputLayout greater control over the visual aspects of any
* text input. An example usage is as so:
@@ -219,7 +229,7 @@ public class TextInputLayout extends LinearLayout {
R.styleable.TextInputLayout_counterOverflowTextAppearance, 0);
mPasswordToggleEnabled = a.getBoolean(
- R.styleable.TextInputLayout_passwordToggleEnabled, true);
+ R.styleable.TextInputLayout_passwordToggleEnabled, false);
mPasswordToggleDrawable = a.getDrawable(R.styleable.TextInputLayout_passwordToggleDrawable);
mPasswordToggleContentDesc = a.getText(
R.styleable.TextInputLayout_passwordToggleContentDescription);
@@ -1041,11 +1051,15 @@ public class TextInputLayout extends LinearLayout {
mPasswordToggleView.setVisibility(View.GONE);
}
- // Make sure that we remove the dummy end compound drawable
- final Drawable[] compounds = TextViewCompat.getCompoundDrawablesRelative(mEditText);
- if (compounds[2] == mPasswordToggleDummyDrawable) {
- TextViewCompat.setCompoundDrawablesRelative(mEditText, compounds[0], compounds[1],
- mOriginalEditTextEndDrawable, compounds[3]);
+ if (mPasswordToggleDummyDrawable != null) {
+ // Make sure that we remove the dummy end compound drawable if it exists, and then
+ // clear it
+ final Drawable[] compounds = TextViewCompat.getCompoundDrawablesRelative(mEditText);
+ if (compounds[2] == mPasswordToggleDummyDrawable) {
+ TextViewCompat.setCompoundDrawablesRelative(mEditText, compounds[0],
+ compounds[1], mOriginalEditTextEndDrawable, compounds[3]);
+ mPasswordToggleDummyDrawable = null;
+ }
}
}
}
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
index 0ddbc6d51d..09a9c35ada 100644
--- a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
+++ b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
@@ -42,6 +42,7 @@ import android.support.annotation.ColorInt;
import android.support.design.test.R;
import android.support.design.testutils.TestDrawable;
import android.support.design.testutils.TestUtilsMatchers;
+import android.support.test.annotation.UiThreadTest;
import android.support.v4.content.res.ResourcesCompat;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.Menu;
@@ -77,6 +78,20 @@ public class BottomNavigationViewTest
mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
}
+ @UiThreadTest
+ @Test
+ @SmallTest
+ public void testAddItemsWithoutMenuInflation() {
+ BottomNavigationView navigation = new BottomNavigationView(mActivityTestRule.getActivity());
+ mActivityTestRule.getActivity().setContentView(navigation);
+ navigation.getMenu().add("Item1");
+ navigation.getMenu().add("Item2");
+ assertEquals(2, navigation.getMenu().size());
+ navigation.getMenu().removeItem(0);
+ navigation.getMenu().removeItem(0);
+ assertEquals(0, navigation.getMenu().size());
+ }
+
@Test
@SmallTest
public void testBasics() {
@@ -196,4 +211,27 @@ public class BottomNavigationViewTest
onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
matches(TestUtilsMatchers.drawable(blueFill, allowedComponentVariance)));
}
+
+ @UiThreadTest
+ @Test
+ @SmallTest
+ public void testItemChecking() throws Throwable {
+ final Menu menu = mBottomNavigation.getMenu();
+ assertTrue(menu.getItem(0).isChecked());
+ checkAndVerifyExclusiveItem(menu, R.id.destination_home);
+ checkAndVerifyExclusiveItem(menu, R.id.destination_profile);
+ checkAndVerifyExclusiveItem(menu, R.id.destination_people);
+ }
+
+ private void checkAndVerifyExclusiveItem(final Menu menu, final int id) throws Throwable {
+ menu.findItem(id).setChecked(true);
+ for (int i = 0; i < menu.size(); i++) {
+ final MenuItem item = menu.getItem(i);
+ if (item.getItemId() == id) {
+ assertTrue(item.isChecked());
+ } else {
+ assertFalse(item.isChecked());
+ }
+ }
+ }
}
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
index 9fff6a24ae..47919a75c1 100644
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/CoordinatorLayoutTest.java
@@ -19,6 +19,7 @@ package android.support.design.widget;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.atLeastOnce;
@@ -392,4 +393,93 @@ public class CoordinatorLayoutTest extends BaseInstrumentationTestCase<Coordinat
// Wait for a layout.
mInstrumentation.waitForIdleSync();
}
+
+ @Test
+ public void testGoneNotMeasuredLaidOut() throws Throwable {
+ final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+ final CoordinatorLayout col = activity.mCoordinatorLayout;
+
+ // Now create a GONE view and add it to the CoordinatorLayout
+ final View imageView = new View(activity);
+ imageView.setVisibility(View.GONE);
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ col.addView(imageView, 200, 200);
+ }
+ });
+ // Wait for a layout and measure pass
+ mInstrumentation.waitForIdleSync();
+
+ // And assert that it has not been laid out
+ assertFalse(imageView.getMeasuredWidth() > 0);
+ assertFalse(imageView.getMeasuredHeight() > 0);
+ assertFalse(ViewCompat.isLaidOut(imageView));
+
+ // Now set the view to INVISIBLE
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ imageView.setVisibility(View.INVISIBLE);
+ }
+ });
+ // Wait for a layout and measure pass
+ mInstrumentation.waitForIdleSync();
+
+ // And assert that it has been laid out
+ assertTrue(imageView.getMeasuredWidth() > 0);
+ assertTrue(imageView.getMeasuredHeight() > 0);
+ assertTrue(ViewCompat.isLaidOut(imageView));
+ }
+
+ @Test
+ public void testDodgeInsetViewWithEmptyBounds() throws Throwable {
+ final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+ // Add a view with zero height/width which is set to dodge its bounds
+ final View view = new View(col.getContext());
+ final Behavior spyBehavior = spy(new DodgeBoundsBehavior());
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
+ lp.dodgeInsetEdges = Gravity.BOTTOM;
+ lp.gravity = Gravity.BOTTOM;
+ lp.height = 0;
+ lp.width = 0;
+ lp.setBehavior(spyBehavior);
+ col.addView(view, lp);
+ }
+ });
+
+ // Wait for a layout
+ mInstrumentation.waitForIdleSync();
+
+ // Now add an non-empty bounds inset view to the bottom of the CoordinatorLayout
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final View dodge = new View(col.getContext());
+ final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
+ lp.insetEdge = Gravity.BOTTOM;
+ lp.gravity = Gravity.BOTTOM;
+ lp.height = 60;
+ lp.width = CoordinatorLayout.LayoutParams.MATCH_PARENT;
+ col.addView(dodge, lp);
+ }
+ });
+
+ // Verify that the Behavior of the view with empty bounds does not have its
+ // getInsetDodgeRect() called
+ verify(spyBehavior, never())
+ .getInsetDodgeRect(same(col), same(view), any(Rect.class));
+ }
+
+ public static class DodgeBoundsBehavior extends Behavior<View> {
+ @Override
+ public boolean getInsetDodgeRect(CoordinatorLayout parent, View child, Rect rect) {
+ rect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
+ return true;
+ }
+ }
}
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
index 66ea00b9c0..0d84865585 100755
--- a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
+++ b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
@@ -36,6 +36,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
@@ -46,8 +47,10 @@ import android.support.design.test.R;
import android.support.test.annotation.UiThreadTest;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewAssertion;
+import android.support.v4.widget.TextViewCompat;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
+import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import org.junit.Test;
@@ -217,6 +220,25 @@ public class TextInputLayoutTest extends BaseInstrumentationTestCase<TextInputLa
onView(withId(R.id.textinput_edittext)).check(matches(not(isEnabled())));
}
+ @UiThreadTest
+ @Test
+ public void testExtractUiHintSet() {
+ final Activity activity = mActivityTestRule.getActivity();
+
+ // Set a hint on the TextInputLayout
+ final TextInputLayout layout = (TextInputLayout) activity.findViewById(R.id.textinput);
+ layout.setHint(INPUT_TEXT);
+
+ final EditText editText = (EditText) activity.findViewById(R.id.textinput_edittext);
+
+ // Now manually pass in a EditorInfo to the EditText and make sure it updates the
+ // hintText to our known value
+ final EditorInfo info = new EditorInfo();
+ editText.onCreateInputConnection(info);
+
+ assertEquals(INPUT_TEXT, info.hintText);
+ }
+
/**
* Regression test for b/31663756.
*/
@@ -230,6 +252,68 @@ public class TextInputLayoutTest extends BaseInstrumentationTestCase<TextInputLa
layout.drawableStateChanged();
}
+ @Test
+ public void testMaintainsLeftRightCompoundDrawables() throws Throwable {
+ final Activity activity = mActivityTestRule.getActivity();
+
+ // Set a known set of test compound drawables on the EditText
+ final Drawable left = new ColorDrawable(Color.RED);
+ final Drawable top = new ColorDrawable(Color.GREEN);
+ final Drawable right = new ColorDrawable(Color.BLUE);
+ final Drawable bottom = new ColorDrawable(Color.BLACK);
+
+ final TextInputEditText editText = new TextInputEditText(activity);
+ editText.setCompoundDrawables(left, top, right, bottom);
+
+ // Now add the EditText to a TextInputLayout
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TextInputLayout til = (TextInputLayout)
+ activity.findViewById(R.id.textinput_noedittext);
+ til.addView(editText);
+ }
+ });
+
+ // Finally assert that all of the drawables are untouched
+ final Drawable[] compoundDrawables = editText.getCompoundDrawables();
+ assertSame(left, compoundDrawables[0]);
+ assertSame(top, compoundDrawables[1]);
+ assertSame(right, compoundDrawables[2]);
+ assertSame(bottom, compoundDrawables[3]);
+ }
+
+ @Test
+ public void testMaintainsStartEndCompoundDrawables() throws Throwable {
+ final Activity activity = mActivityTestRule.getActivity();
+
+ // Set a known set of test compound drawables on the EditText
+ final Drawable start = new ColorDrawable(Color.RED);
+ final Drawable top = new ColorDrawable(Color.GREEN);
+ final Drawable end = new ColorDrawable(Color.BLUE);
+ final Drawable bottom = new ColorDrawable(Color.BLACK);
+
+ final TextInputEditText editText = new TextInputEditText(activity);
+ TextViewCompat.setCompoundDrawablesRelative(editText, start, top, end, bottom);
+
+ // Now add the EditText to a TextInputLayout
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ TextInputLayout til = (TextInputLayout)
+ activity.findViewById(R.id.textinput_noedittext);
+ til.addView(editText);
+ }
+ });
+
+ // Finally assert that all of the drawables are untouched
+ final Drawable[] compoundDrawables = TextViewCompat.getCompoundDrawablesRelative(editText);
+ assertSame(start, compoundDrawables[0]);
+ assertSame(top, compoundDrawables[1]);
+ assertSame(end, compoundDrawables[2]);
+ assertSame(bottom, compoundDrawables[3]);
+ }
+
static ViewAssertion isHintExpanded(final boolean expanded) {
return new ViewAssertion() {
@Override
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index df11178b09..31cb13d280 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -52,6 +52,10 @@ android {
testOptions {
unitTests.returnDefaultValues = true
}
+
+ buildTypes.all {
+ consumerProguardFiles 'proguard-rules.pro'
+ }
}
android.libraryVariants.all { variant ->
diff --git a/graphics/drawable/animated/proguard-rules.pro b/graphics/drawable/animated/proguard-rules.pro
new file mode 100644
index 0000000000..4695a39f11
--- /dev/null
+++ b/graphics/drawable/animated/proguard-rules.pro
@@ -0,0 +1,19 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# keep setters in VectorDrawables so that animations can still work.
+-keepclassmembers class android.support.graphics.drawable.VectorDrawableCompat$* {
+ void set*(***);
+ *** get*();
+}
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 0b0522eb05..599631bd61 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -55,12 +55,81 @@ import java.util.List;
* For older API version, this class uses {@link android.animation.ObjectAnimator} and
* {@link android.animation.AnimatorSet} to animate the properties of a
* {@link VectorDrawableCompat} to create an animated drawable.
- * <p>
+ * <p/>
* AnimatedVectorDrawableCompat are defined in the same XML format as {@link AnimatedVectorDrawable}.
- * </p>
+ * <p/>
+ * Here are all the animatable attributes in {@link VectorDrawableCompat}:
+ * <table border="2" align="center" cellpadding="5">
+ * <thead>
+ * <tr>
+ * <th>Element Name</th>
+ * <th>Animatable attribute name</th>
+ * </tr>
+ * </thead>
+ * <tr>
+ * <td>&lt;vector&gt;</td>
+ * <td>alpha</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="7">&lt;group&gt;</td>
+ * <td>rotation</td>
+ * </tr>
+ * <tr>
+ * <td>pivotX</td>
+ * </tr>
+ * <tr>
+ * <td>pivotY</td>
+ * </tr>
+ * <tr>
+ * <td>scaleX</td>
+ * </tr>
+ * <tr>
+ * <td>scaleY</td>
+ * </tr>
+ * <tr>
+ * <td>translateX</td>
+ * </tr>
+ * <tr>
+ * <td>translateY</td>
+ * </tr>
+ * <tr>
+ * <td rowspan="8">&lt;path&gt;</td>
+ * <td>fillColor</td>
+ * </tr>
+ * <tr>
+ * <td>strokeColor</td>
+ * </tr>
+ * <tr>
+ * <td>strokeWidth</td>
+ * </tr>
+ * <tr>
+ * <td>strokeAlpha</td>
+ * </tr>
+ * <tr>
+ * <td>fillAlpha</td>
+ * </tr>
+ * <tr>
+ * <td>trimPathStart</td>
+ * </tr>
+ * <tr>
+ * <td>trimPathOffset</td>
+ * </tr>
+ * </table>
+ * <p/>
* You can always create a AnimatedVectorDrawableCompat object and use it as a Drawable by the Java
* API. In order to refer to AnimatedVectorDrawableCompat inside a XML file, you can use
* app:srcCompat attribute in AppCompat library's ImageButton or ImageView.
+ * <p/>
+ * Note that the animation in AnimatedVectorDrawableCompat has to be valid and functional based on
+ * the SDK version the app will be running on. Before SDK version 21, the animation system didn't
+ * support the following features:
+ * <ul>
+ * <li>Path Morphing (PathType evaluator). This is used for morphing one path into another.</li>
+ * <li>Path Interpolation. This is used to defined a flexible interpolator (represented as a path)
+ * instead of the system defined ones like LinearInterpolator.</li>
+ * <li>Animating 2 values in one ObjectAnimator according to one path's X value and Y value. One
+ * usage is moving one object in both X and Y dimensions along an path.</li>
+ * </ul>
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class AnimatedVectorDrawableCompat extends VectorDrawableCommon implements Animatable {
@@ -99,13 +168,18 @@ public class AnimatedVectorDrawableCompat extends VectorDrawableCommon implement
}
}
+ /**
+ * mutate() will be effective only if the getConstantState() is returning non-null.
+ * Otherwise, it just return the current object without modification.
+ */
@Override
public Drawable mutate() {
if (mDelegateDrawable != null) {
mDelegateDrawable.mutate();
- return this;
}
- throw new IllegalStateException("Mutate() is not supported for older platform");
+ // For older platforms that there is no delegated drawable, we just return this without
+ // any modification here, and the getConstantState() will return null in this case.
+ return this;
}
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java b/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
index 2e50823425..306f5107b0 100644
--- a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
+++ b/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
@@ -268,6 +268,8 @@ public class AnimatedVectorDrawableTest {
assertEquals(0x40, d1.getAlpha());
assertEquals(0x20, d2.getAlpha());
assertEquals(originalAlpha, d3.getAlpha());
+ } else {
+ assertEquals(d1.mutate(), d1);
}
}
}
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 f4d11985fd..1a0f5af5b8 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -52,9 +52,6 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.Stack;
@@ -84,36 +81,27 @@ import java.util.Stack;
* <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>
+ * <dd>The Porter-Duff blending mode for the tint color. Default is src_in.</dd>
* <dt><code>android:autoMirrored</code></dt>
* <dd>Indicates if the drawable needs to be mirrored when its layout direction is
- * RTL (right-to-left).</dd>
- * <dd>Animatable : No.</dd>
+ * RTL (right-to-left). Default is false.</dd>
* <dt><code>android:alpha</code></dt>
- * <dd>The opacity of this drawable.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The opacity of this drawable. Default is 1.</dd>
* </dl></dd>
* </dl>
*
@@ -125,32 +113,24 @@ import java.util.Stack;
* <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>
+ * <dd>The degrees of rotation of the group. Default is 0.</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>
+ * This is defined in the viewport space. Default is 0.</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>
+ * This is defined in the viewport space. Default is 0.</dd>
* <dt><code>android:scaleX</code></dt>
- * <dd>The amount of scale on the X Coordinate.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The amount of scale on the X Coordinate. Default is 1.</dd>
* <dt><code>android:scaleY</code></dt>
- * <dd>The amount of scale on the Y coordinate.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The amount of scale on the Y coordinate. Default is 1.</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>
+ * This is defined in the viewport space. Default is 0.</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>
+ * This is defined in the viewport space. Default is 0.</dd>
* </dl></dd>
* </dl>
*
@@ -160,49 +140,36 @@ import java.util.Stack;
* <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>
+ * <dd>The width a path stroke. Default is 0.</dd>
* <dt><code>android:strokeAlpha</code></dt>
- * <dd>The opacity of a path stroke.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The opacity of a path stroke. Default is 1.</dd>
* <dt><code>android:fillAlpha</code></dt>
- * <dd>The opacity to fill the path with.</dd>
- * <dd>Animatable : Yes.</dd>
+ * <dd>The opacity to fill the path with. Default is 1.</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>
+ * <dd>The fraction of the path to trim from the start, in the range from 0 to 1. Default is 0.</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>
+ * <dd>The fraction of the path to trim from the end, in the range from 0 to 1. Default is 1.</dd>
* <dt><code>android:trimPathOffset</code></dt>
* <dd>Shift trim region (allows showed region to include the start and end), in the range
- * from 0 to 1.</dd>
- * <dd>Animatable : Yes.</dd>
+ * from 0 to 1. Default is 0.</dd>
* <dt><code>android:strokeLineCap</code></dt>
- * <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>Sets the linecap for a stroked path: butt, round, square. Default is butt.</dd>
* <dt><code>android:strokeLineJoin</code></dt>
- * <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>Sets the lineJoin for a stroked path: miter,round,bevel. Default is miter.</dd>
* <dt><code>android:strokeMiterLimit</code></dt>
- * <dd>Sets the Miter limit for a stroked path.</dd>
- * <dd>Animatable : No.</dd>
+ * <dd>Sets the Miter limit for a stroked path. Default is 4.</dd>
* </dl></dd>
* </dl>
*
@@ -213,13 +180,14 @@ import java.util.Stack;
* <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>
+ * <p/>
+ * Note that theme attributes in XML file are supported through
+ * <code>{@link #inflate(Resources, XmlPullParser, AttributeSet, Theme)}</code>.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
index 1fe0da9d71..79f61c31a5 100644
--- a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
+++ b/media-compat/java/android/support/v4/media/MediaBrowserCompat.java
@@ -1784,7 +1784,9 @@ public final class MediaBrowserCompat {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
- resultData.setClassLoader(MediaBrowserCompat.class.getClassLoader());
+ if (resultData != null) {
+ resultData.setClassLoader(MediaBrowserCompat.class.getClassLoader());
+ }
if (resultCode != 0 || resultData == null
|| !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
mCallback.onError(mMediaId);
diff --git a/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml b/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml
index aa07328937..1c60d90cbf 100644
--- a/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml
+++ b/samples/Support7Demos/res/layout/appcompat_widgets_buttons.xml
@@ -16,8 +16,9 @@
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -77,6 +78,19 @@
android:text="Button (borderless + colored)"
style="@style/Widget.AppCompat.Button.Borderless.Colored"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button (colored)"
+ style="@style/Widget.AppCompat.Button.Colored"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button (colored + tinted)"
+ app:backgroundTint="#00FF00"
+ style="@style/Widget.AppCompat.Button.Colored"/>
+
<RatingBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
diff --git a/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
index c86843009a..b2a4d59b09 100644
--- a/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
+++ b/samples/SupportDesignDemos/res/layout/design_bottom_navigation_view.xml
@@ -52,11 +52,18 @@
android:text="@string/bottomnavigation_tint"
android:layout_below="@+id/button_remove"/>
+ <Button
+ android:id="@+id/button_select_next"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bottomnavigation_select_next"
+ android:layout_below="@+id/button_tint"/>
+
<TextView
android:id="@+id/selected_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@+id/button_tint"/>
+ android:layout_below="@+id/button_select_next"/>
</RelativeLayout>
</ScrollView>
<android.support.design.widget.BottomNavigationView
@@ -64,6 +71,6 @@
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="bottom"
- android:background="#eee"
+ android:background="#fafafa"
app:menu="@menu/sample_bottom_menu"/>
</FrameLayout>
diff --git a/samples/SupportDesignDemos/res/values/strings.xml b/samples/SupportDesignDemos/res/values/strings.xml
index 95900ca163..c257f1de5f 100644
--- a/samples/SupportDesignDemos/res/values/strings.xml
+++ b/samples/SupportDesignDemos/res/values/strings.xml
@@ -127,4 +127,5 @@
<string name="bottomnavigation_add">Add an item</string>
<string name="bottomnavigation_remove">Remove an item</string>
<string name="bottomnavigation_tint">Toggle tint</string>
+ <string name="bottomnavigation_select_next">Select next item</string>
</resources>
diff --git a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
index 34422181ea..fa9b0b6705 100644
--- a/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
+++ b/samples/SupportDesignDemos/src/com/example/android/support/design/widget/BottomNavigationViewUsage.java
@@ -76,6 +76,20 @@ public class BottomNavigationViewUsage extends AppCompatActivity {
}
}
});
+ Button buttonNext = (Button) findViewById(R.id.button_select_next);
+ buttonNext.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ final int menuSize = bottom.getMenu().size();
+ int currentlySelected = 0;
+ for (int i = 0; i < menuSize; i++) {
+ if (bottom.getMenu().getItem(i).isChecked()) {
+ currentlySelected = i;
+ }
+ }
+ bottom.getMenu().getItem((currentlySelected + 1) % menuSize).setChecked(true);
+ }
+ });
final TextView selectedItem = (TextView) findViewById(R.id.selected_item);
bottom.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
diff --git a/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
index c485ca6724..a9335d084d 100644
--- a/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
+++ b/v13/api25/android/support/v13/view/inputmethod/InputContentInfoCompatApi25.java
@@ -44,6 +44,6 @@ final class InputContentInfoCompatApi25 {
}
public static void releasePermission(Object inputContentInfo) {
- ((InputContentInfo) inputContentInfo).requestPermission();
+ ((InputContentInfo) inputContentInfo).releasePermission();
}
}
diff --git a/v17/leanback/res/layout/lb_guidedstep_fragment.xml b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
index adf9d4f404..bbe21ba73f 100644
--- a/v17/leanback/res/layout/lb_guidedstep_fragment.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
@@ -33,6 +33,7 @@
<LinearLayout
android:id="@+id/content_frame"
android:orientation="horizontal"
+ android:baselineAligned="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -40,8 +41,7 @@
android:id="@+id/content_fragment"
android:layout_width="0dp"
android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true" />
+ android:layout_height="match_parent" />
<android.support.v17.leanback.widget.NonOverlappingFrameLayout
android:id="@+id/action_fragment_root"
@@ -53,8 +53,7 @@
android:paddingStart="@dimen/lb_guidedactions_section_shadow_width"
android:layout_width="0dp"
android:layout_weight="?attr/guidedActionContentWidthWeight"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true">
+ android:layout_height="match_parent" >
<android.support.v17.leanback.widget.NonOverlappingView
android:id="@+id/action_fragment_background"
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java
index 72cb5a15eb..aef967891d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java
@@ -15,8 +15,8 @@
*/
package android.support.v17.leanback.app;
-import android.support.annotation.RestrictTo;
import android.support.v4.app.Fragment;
+import android.support.annotation.RestrictTo;
import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 0f7cfa0b2c..be56ea5f34 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -1006,11 +1006,8 @@ public class BrowseFragment extends BaseFragment {
mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
return true;
}
- if (getTitleView() != null &&
- getTitleView().requestFocus(direction, previouslyFocusedRect)) {
- return true;
- }
- return false;
+ return getTitleView() != null &&
+ getTitleView().requestFocus(direction, previouslyFocusedRect);
}
@Override
@@ -1120,8 +1117,8 @@ public class BrowseFragment extends BaseFragment {
.getMainFragmentAdapter();
mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
- mIsPageRow = savedInstanceState != null ?
- savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
+ mIsPageRow = savedInstanceState != null
+ && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
mSelectedPosition = savedInstanceState != null ?
savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index c88438e280..d85a93a9a3 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -1008,11 +1008,8 @@ public class BrowseSupportFragment extends BaseSupportFragment {
mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
return true;
}
- if (getTitleView() != null &&
- getTitleView().requestFocus(direction, previouslyFocusedRect)) {
- return true;
- }
- return false;
+ return getTitleView() != null &&
+ getTitleView().requestFocus(direction, previouslyFocusedRect);
}
@Override
@@ -1122,8 +1119,8 @@ public class BrowseSupportFragment extends BaseSupportFragment {
.getMainFragmentAdapter();
mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
- mIsPageRow = savedInstanceState != null ?
- savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
+ mIsPageRow = savedInstanceState != null
+ && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
mSelectedPosition = savedInstanceState != null ?
savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
index f5b27df281..2552f8000b 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -17,7 +17,6 @@ package android.support.v17.leanback.app;
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.support.annotation.RestrictTo;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@@ -27,6 +26,7 @@ import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
import android.support.v17.leanback.R;
import android.support.v17.leanback.transition.TransitionHelper;
import android.support.v17.leanback.widget.GuidanceStylist;
@@ -1317,6 +1317,7 @@ public class GuidedStepSupportFragment extends Fragment implements GuidedActionA
* For now clients(subclasses) can call this method inside the constructor.
* @hide
*/
+ @RestrictTo(GROUP_ID)
public void setEntranceTransitionType(int transitionType) {
this.entranceTransitionType = transitionType;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
index 2cf897ff25..888e0575aa 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -21,6 +21,8 @@ import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.View;
+import java.lang.ref.WeakReference;
+
/**
* A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and
@@ -178,14 +180,21 @@ public abstract class PlaybackControlGlue implements OnActionClickedListener, Vi
private int mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
private boolean mFadeWhenPlaying = true;
- private final Handler mHandler = new Handler() {
+ static class UpdatePlaybackStateHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_UPDATE_PLAYBACK_STATE) {
- updatePlaybackState();
+ PlaybackControlGlue glue = ((WeakReference<PlaybackControlGlue>) msg.obj).get();
+ if (glue != null) {
+ glue.updatePlaybackState();
+ }
}
}
- };
+ }
+
+ final static Handler sHandler = new UpdatePlaybackStateHandler();
+
+ final WeakReference<PlaybackControlGlue> mGlueWeakReference = new WeakReference(this);
private final OnItemViewClickedListener mOnItemViewClickedListener =
new OnItemViewClickedListener() {
@@ -561,16 +570,16 @@ public abstract class PlaybackControlGlue implements OnActionClickedListener, Vi
private void updateControlsRow() {
updateRowMetadata();
- mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
updatePlaybackState();
}
private void updatePlaybackStatusAfterUserAction() {
updatePlaybackState(mPlaybackSpeed);
// Sync playback state after a delay
- mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
- mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
- UPDATE_PLAYBACK_STATE_DELAY_MS);
+ sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
+ sHandler.sendMessageDelayed(sHandler.obtainMessage(MSG_UPDATE_PLAYBACK_STATE,
+ mGlueWeakReference), UPDATE_PLAYBACK_STATE_DELAY_MS);
}
private void updateRowMetadata() {
@@ -831,12 +840,12 @@ public abstract class PlaybackControlGlue implements OnActionClickedListener, Vi
if (!hasValidMedia()) {
return;
}
- if (mHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE)) {
- mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ if (sHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference)) {
+ sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
if (getCurrentSpeedId() != mPlaybackSpeed) {
if (DEBUG) Log.v(TAG, "Status expectation mismatch, delaying update");
- mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
- UPDATE_PLAYBACK_STATE_DELAY_MS);
+ sHandler.sendMessageDelayed(sHandler.obtainMessage(MSG_UPDATE_PLAYBACK_STATE,
+ mGlueWeakReference), UPDATE_PLAYBACK_STATE_DELAY_MS);
} else {
if (DEBUG) Log.v(TAG, "Update state matches expectation");
updatePlaybackState();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
index 1e1eab5094..e8068ec05b 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
@@ -23,6 +23,8 @@ import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.View;
+import java.lang.ref.WeakReference;
+
/**
* A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and
@@ -180,14 +182,21 @@ public abstract class PlaybackControlSupportGlue implements OnActionClickedListe
private int mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
private boolean mFadeWhenPlaying = true;
- private final Handler mHandler = new Handler() {
+ static class UpdatePlaybackStateHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_UPDATE_PLAYBACK_STATE) {
- updatePlaybackState();
+ PlaybackControlSupportGlue glue = ((WeakReference<PlaybackControlSupportGlue>) msg.obj).get();
+ if (glue != null) {
+ glue.updatePlaybackState();
+ }
}
}
- };
+ }
+
+ final static Handler sHandler = new UpdatePlaybackStateHandler();
+
+ final WeakReference<PlaybackControlSupportGlue> mGlueWeakReference = new WeakReference(this);
private final OnItemViewClickedListener mOnItemViewClickedListener =
new OnItemViewClickedListener() {
@@ -494,14 +503,18 @@ public abstract class PlaybackControlSupportGlue implements OnActionClickedListe
boolean canPause = keyEvent == null ||
keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE;
- if (mPlaybackSpeed != PLAYBACK_SPEED_NORMAL) {
- if (canPlay) {
- mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
- startPlayback(mPlaybackSpeed);
- }
- } else if (canPause) {
+ // PLAY_PAUSE PLAY PAUSE
+ // playing paused paused
+ // paused playing playing
+ // ff/rw playing playing paused
+ if (canPause &&
+ (canPlay ? mPlaybackSpeed == PLAYBACK_SPEED_NORMAL :
+ mPlaybackSpeed != PLAYBACK_SPEED_PAUSED)) {
mPlaybackSpeed = PLAYBACK_SPEED_PAUSED;
pausePlayback();
+ } else if (canPlay && mPlaybackSpeed != PLAYBACK_SPEED_NORMAL) {
+ mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
+ startPlayback(mPlaybackSpeed);
}
updatePlaybackStatusAfterUserAction();
handled = true;
@@ -559,16 +572,16 @@ public abstract class PlaybackControlSupportGlue implements OnActionClickedListe
private void updateControlsRow() {
updateRowMetadata();
- mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
updatePlaybackState();
}
private void updatePlaybackStatusAfterUserAction() {
updatePlaybackState(mPlaybackSpeed);
// Sync playback state after a delay
- mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
- mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
- UPDATE_PLAYBACK_STATE_DELAY_MS);
+ sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
+ sHandler.sendMessageDelayed(sHandler.obtainMessage(MSG_UPDATE_PLAYBACK_STATE,
+ mGlueWeakReference), UPDATE_PLAYBACK_STATE_DELAY_MS);
}
private void updateRowMetadata() {
@@ -829,12 +842,12 @@ public abstract class PlaybackControlSupportGlue implements OnActionClickedListe
if (!hasValidMedia()) {
return;
}
- if (mHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE)) {
- mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
+ if (sHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference)) {
+ sHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE, mGlueWeakReference);
if (getCurrentSpeedId() != mPlaybackSpeed) {
if (DEBUG) Log.v(TAG, "Status expectation mismatch, delaying update");
- mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
- UPDATE_PLAYBACK_STATE_DELAY_MS);
+ sHandler.sendMessageDelayed(sHandler.obtainMessage(MSG_UPDATE_PLAYBACK_STATE,
+ mGlueWeakReference), UPDATE_PLAYBACK_STATE_DELAY_MS);
} else {
if (DEBUG) Log.v(TAG, "Update state matches expectation");
updatePlaybackState();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
index 58eb2cb560..86e171b996 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
@@ -47,6 +47,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -131,9 +132,7 @@ public class PlaybackOverlayFragment extends DetailsFragment {
private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator;
private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
- private boolean mTranslateAnimationEnabled;
boolean mResetControlsToPrimaryActionsPending;
- private RecyclerView.ItemAnimator mItemAnimator;
private final Animator.AnimatorListener mFadeListener =
new Animator.AnimatorListener() {
@@ -170,14 +169,22 @@ public class PlaybackOverlayFragment extends DetailsFragment {
}
};
- private final Handler mHandler = new Handler() {
+ static class FadeHandler extends Handler {
@Override
public void handleMessage(Message message) {
- if (message.what == START_FADE_OUT && mFadingEnabled) {
- fade(false);
+ PlaybackOverlayFragment fragment;
+ if (message.what == START_FADE_OUT) {
+ fragment = ((WeakReference<PlaybackOverlayFragment>) message.obj).get();
+ if (fragment != null && fragment.mFadingEnabled) {
+ fragment.fade(false);
+ }
}
}
- };
+ }
+
+ final static Handler sHandler = new FadeHandler();
+
+ final WeakReference<PlaybackOverlayFragment> mFragmentReference = new WeakReference(this);
private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
new VerticalGridView.OnTouchInterceptListener() {
@@ -234,12 +241,12 @@ public class PlaybackOverlayFragment extends DetailsFragment {
mFadingEnabled = enabled;
if (mFadingEnabled) {
if (isResumed() && mFadingStatus == IDLE
- && !mHandler.hasMessages(START_FADE_OUT)) {
+ && !sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
startFadeTimer();
}
} else {
// Ensure fully opaque
- mHandler.removeMessages(START_FADE_OUT);
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
fade(true);
}
}
@@ -290,7 +297,7 @@ public class PlaybackOverlayFragment extends DetailsFragment {
if (!mFadingEnabled || !isResumed()) {
return;
}
- if (mHandler.hasMessages(START_FADE_OUT)) {
+ if (sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
// Restart the timer
startFadeTimer();
} else {
@@ -302,7 +309,7 @@ public class PlaybackOverlayFragment extends DetailsFragment {
* Fades out the playback overlay immediately.
*/
public void fadeOut() {
- mHandler.removeMessages(START_FADE_OUT);
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
fade(false);
}
@@ -342,7 +349,7 @@ public class PlaybackOverlayFragment extends DetailsFragment {
// them out (even if the key was consumed by the handler).
if (mFadingEnabled && !controlsHidden) {
consumeEvent = true;
- mHandler.removeMessages(START_FADE_OUT);
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
fade(false);
} else if (consumeEvent) {
tickle();
@@ -368,10 +375,9 @@ public class PlaybackOverlayFragment extends DetailsFragment {
}
void startFadeTimer() {
- if (mHandler != null) {
- mHandler.removeMessages(START_FADE_OUT);
- mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
- }
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
+ sHandler.sendMessageDelayed(sHandler.obtainMessage(START_FADE_OUT, mFragmentReference),
+ mShowTimeMs);
}
private static ValueAnimator loadAnimator(Context context, int resId) {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
index 2c103a7846..baf2b89111 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
@@ -49,6 +49,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -133,9 +134,7 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
private ValueAnimator mDescriptionFadeInAnimator, mDescriptionFadeOutAnimator;
private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
- private boolean mTranslateAnimationEnabled;
boolean mResetControlsToPrimaryActionsPending;
- private RecyclerView.ItemAnimator mItemAnimator;
private final Animator.AnimatorListener mFadeListener =
new Animator.AnimatorListener() {
@@ -172,14 +171,22 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
}
};
- private final Handler mHandler = new Handler() {
+ static class FadeHandler extends Handler {
@Override
public void handleMessage(Message message) {
- if (message.what == START_FADE_OUT && mFadingEnabled) {
- fade(false);
+ PlaybackOverlaySupportFragment fragment;
+ if (message.what == START_FADE_OUT) {
+ fragment = ((WeakReference<PlaybackOverlaySupportFragment>) message.obj).get();
+ if (fragment != null && fragment.mFadingEnabled) {
+ fragment.fade(false);
+ }
}
}
- };
+ }
+
+ final static Handler sHandler = new FadeHandler();
+
+ final WeakReference<PlaybackOverlaySupportFragment> mFragmentReference = new WeakReference(this);
private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
new VerticalGridView.OnTouchInterceptListener() {
@@ -236,12 +243,12 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
mFadingEnabled = enabled;
if (mFadingEnabled) {
if (isResumed() && mFadingStatus == IDLE
- && !mHandler.hasMessages(START_FADE_OUT)) {
+ && !sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
startFadeTimer();
}
} else {
// Ensure fully opaque
- mHandler.removeMessages(START_FADE_OUT);
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
fade(true);
}
}
@@ -292,7 +299,7 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
if (!mFadingEnabled || !isResumed()) {
return;
}
- if (mHandler.hasMessages(START_FADE_OUT)) {
+ if (sHandler.hasMessages(START_FADE_OUT, mFragmentReference)) {
// Restart the timer
startFadeTimer();
} else {
@@ -304,7 +311,7 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
* Fades out the playback overlay immediately.
*/
public void fadeOut() {
- mHandler.removeMessages(START_FADE_OUT);
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
fade(false);
}
@@ -344,7 +351,7 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
// them out (even if the key was consumed by the handler).
if (mFadingEnabled && !controlsHidden) {
consumeEvent = true;
- mHandler.removeMessages(START_FADE_OUT);
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
fade(false);
} else if (consumeEvent) {
tickle();
@@ -370,10 +377,9 @@ public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
}
void startFadeTimer() {
- if (mHandler != null) {
- mHandler.removeMessages(START_FADE_OUT);
- mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
- }
+ sHandler.removeMessages(START_FADE_OUT, mFragmentReference);
+ sHandler.sendMessageDelayed(sHandler.obtainMessage(START_FADE_OUT, mFragmentReference),
+ mShowTimeMs);
}
private static ValueAnimator loadAnimator(Context context, int resId) {
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 5b72643817..4837a3b642 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
@@ -48,11 +48,8 @@ public final class TransitionHelper {
* @return True if Transition animations are supported.
*/
public static boolean systemSupportsTransitions() {
- if (Build.VERSION.SDK_INT >= 19) {
- // Supported on Android 4.4 or later.
- return true;
- }
- return false;
+ // Supported on Android 4.4 or later.
+ return Build.VERSION.SDK_INT >= 19;
}
/**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
index 82f5cfb5c0..1db870a39d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
@@ -847,10 +847,7 @@ abstract class BaseGridView extends RecyclerView {
if (super.dispatchKeyEvent(event)) {
return true;
}
- if (mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event)) {
- return true;
- }
- return false;
+ return mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event);
}
@Override
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
index 937d328d53..e18276397e 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
@@ -32,13 +32,34 @@ import android.view.View.MeasureSpec;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
+import java.lang.ref.WeakReference;
import java.util.List;
final class DetailsOverviewSharedElementHelper extends SharedElementCallback {
- static final String TAG = "DetailsOverviewSharedElementHelper";
+ static final String TAG = "DetailsTransitionHelper";
static final boolean DEBUG = false;
+ static class TransitionTimeOutRunnable implements Runnable {
+ WeakReference<DetailsOverviewSharedElementHelper> mHelperRef;
+
+ TransitionTimeOutRunnable(DetailsOverviewSharedElementHelper helper) {
+ mHelperRef = new WeakReference<DetailsOverviewSharedElementHelper>(helper);
+ }
+
+ @Override
+ public void run() {
+ DetailsOverviewSharedElementHelper helper = mHelperRef.get();
+ if (helper == null) {
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "timeout " + helper.mActivityToRunTransition);
+ }
+ helper.startPostponedEnterTransition();
+ }
+ }
+
ViewHolder mViewHolder;
Activity mActivityToRunTransition;
boolean mStartedPostpone;
@@ -182,18 +203,7 @@ final class DetailsOverviewSharedElementHelper extends SharedElementCallback {
ActivityCompat.setEnterSharedElementCallback(mActivityToRunTransition, this);
ActivityCompat.postponeEnterTransition(mActivityToRunTransition);
if (timeoutMs > 0) {
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- if (mStartedPostpone) {
- return;
- }
- if (DEBUG) {
- Log.d(TAG, "timeout " + mActivityToRunTransition);
- }
- startPostponedEnterTransition();
- }
- }, timeoutMs);
+ new Handler().postDelayed(new TransitionTimeOutRunnable(this), timeoutMs);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
index 9fd8815612..7fbb0e6ea9 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
@@ -34,6 +34,8 @@ import android.widget.ImageView.ScaleType;
import java.util.List;
+import java.lang.ref.WeakReference;
+
/**
* Helper class to assist delayed shared element activity transition for view created by
* {@link FullWidthDetailsOverviewRowPresenter}. User must call
@@ -46,11 +48,31 @@ import java.util.List;
public class FullWidthDetailsOverviewSharedElementHelper extends
FullWidthDetailsOverviewRowPresenter.Listener {
- static final String TAG = "FullWidthDetailsOverviewSharedElementHelper";
+ static final String TAG = "DetailsTransitionHelper";
static final boolean DEBUG = false;
private static final long DEFAULT_TIMEOUT = 5000;
+ static class TransitionTimeOutRunnable implements Runnable {
+ WeakReference<FullWidthDetailsOverviewSharedElementHelper> mHelperRef;
+
+ TransitionTimeOutRunnable(FullWidthDetailsOverviewSharedElementHelper helper) {
+ mHelperRef = new WeakReference<FullWidthDetailsOverviewSharedElementHelper>(helper);
+ }
+
+ @Override
+ public void run() {
+ FullWidthDetailsOverviewSharedElementHelper helper = mHelperRef.get();
+ if (helper == null) {
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "timeout " + helper.mActivityToRunTransition);
+ }
+ helper.startPostponedEnterTransition();
+ }
+ }
+
ViewHolder mViewHolder;
Activity mActivityToRunTransition;
private boolean mStartedPostpone;
@@ -80,15 +102,7 @@ public class FullWidthDetailsOverviewSharedElementHelper extends
setAutoStartSharedElementTransition(transition != null);
ActivityCompat.postponeEnterTransition(mActivityToRunTransition);
if (timeoutMs > 0) {
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "timeout " + mActivityToRunTransition);
- }
- startPostponedEnterTransitionInternal();
- }
- }, timeoutMs);
+ new Handler().postDelayed(new TransitionTimeOutRunnable(this), timeoutMs);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
index 7f28705008..888cc8fa00 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
@@ -184,11 +184,17 @@ public class GuidanceStylist implements FragmentAnimationProvider {
if (mGuidanceContainer != null) {
CharSequence contentDescription = mGuidanceContainer.getContentDescription();
if (TextUtils.isEmpty(contentDescription)) {
- mGuidanceContainer.setContentDescription(new StringBuilder()
- .append(guidance.getBreadcrumb()).append('\n')
- .append(guidance.getTitle()).append('\n')
- .append(guidance.getDescription())
- .toString());
+ StringBuilder builder = new StringBuilder();
+ if (!TextUtils.isEmpty(guidance.getBreadcrumb())) {
+ builder.append(guidance.getBreadcrumb()).append('\n');
+ }
+ if (!TextUtils.isEmpty(guidance.getTitle())) {
+ builder.append(guidance.getTitle()).append('\n');
+ }
+ if (!TextUtils.isEmpty(guidance.getDescription())) {
+ builder.append(guidance.getDescription()).append('\n');
+ }
+ mGuidanceContainer.setContentDescription(builder);
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
index 200b6d93a5..9d86bfee78 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
@@ -437,12 +437,9 @@ public class ListRowPresenter extends RowPresenter {
new BaseGridView.OnUnhandledKeyListener() {
@Override
public boolean onUnhandledKey(KeyEvent event) {
- if (rowViewHolder.getOnKeyListener() != null &&
+ return rowViewHolder.getOnKeyListener() != null &&
rowViewHolder.getOnKeyListener().onKey(
- rowViewHolder.view, event.getKeyCode(), event)) {
- return true;
- }
- return false;
+ rowViewHolder.view, event.getKeyCode(), event);
}
});
rowViewHolder.mGridView.setNumRows(mNumRows);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java b/v17/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java
index 8242caa8b5..e08a0ec241 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java
@@ -60,6 +60,7 @@ class NonOverlappingLinearLayoutWithForeground extends LinearLayout {
if (d != null) {
setForegroundCompat(d);
}
+ a.recycle();
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java
index 277f427a12..c10d202871 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java
@@ -57,10 +57,7 @@ class PlaybackControlsRowView extends LinearLayout {
if (super.dispatchKeyEvent(event)) {
return true;
}
- if (mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event)) {
- return true;
- }
- return false;
+ return mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event);
}
@Override
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
index 5e52a2215b..e01a168c61 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
@@ -36,25 +36,19 @@ public class BrowseFragmentTestActivity extends Activity {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
- BrowseTestFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
- BrowseTestFragment.DEFAULT_NUM_ROWS);
- BrowseTestFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
- BrowseTestFragment.DEFAULT_REPEAT_PER_ROW);
- BrowseTestFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
- BrowseTestFragment.DEFAULT_LOAD_DATA_DELAY);
- BrowseTestFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
- EXTRA_TEST_ENTRANCE_TRANSITION,
- BrowseTestFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
- BrowseTestFragment.SET_ADAPTER_AFTER_DATA_LOAD = intent.getBooleanExtra(
- EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
- BrowseTestFragment.DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
setContentView(R.layout.browse);
- FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.replace(R.id.main_frame, new BrowseTestFragment());
- if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
- ft.addToBackStack(null);
+ if (savedInstanceState == null) {
+ Bundle arguments = new Bundle();
+ arguments.putAll(intent.getExtras());
+ BrowseTestFragment fragment = new BrowseTestFragment();
+ fragment.setArguments(arguments);
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(R.id.main_frame, fragment);
+ if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+ ft.addToBackStack(null);
+ }
+ ft.commit();
}
- ft.commit();
}
public BrowseTestFragment getBrowseTestFragment() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
index d92b58deca..14f72bc957 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
@@ -38,25 +38,19 @@ public class BrowseSupportFragmentTestActivity extends FragmentActivity {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
- BrowseTestSupportFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
- BrowseTestSupportFragment.DEFAULT_NUM_ROWS);
- BrowseTestSupportFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
- BrowseTestSupportFragment.DEFAULT_REPEAT_PER_ROW);
- BrowseTestSupportFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
- BrowseTestSupportFragment.DEFAULT_LOAD_DATA_DELAY);
- BrowseTestSupportFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
- EXTRA_TEST_ENTRANCE_TRANSITION,
- BrowseTestSupportFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
- BrowseTestSupportFragment.SET_ADAPTER_AFTER_DATA_LOAD = intent.getBooleanExtra(
- EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
- BrowseTestSupportFragment.DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
setContentView(R.layout.browse);
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.replace(R.id.main_frame, new BrowseTestSupportFragment());
- if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
- ft.addToBackStack(null);
+ if (savedInstanceState == null) {
+ Bundle arguments = new Bundle();
+ arguments.putAll(intent.getExtras());
+ BrowseTestSupportFragment fragment = new BrowseTestSupportFragment();
+ fragment.setArguments(arguments);
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+ ft.replace(R.id.main_frame, fragment);
+ if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+ ft.addToBackStack(null);
+ }
+ ft.commit();
}
- ft.commit();
}
public BrowseTestSupportFragment getBrowseTestSupportFragment() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
index 62fa32e963..8de428b7c0 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
@@ -28,6 +28,11 @@ import android.support.v17.leanback.widget.VerticalGridView;
import android.util.Log;
import android.view.View;
+import static android.support.v17.leanback.app.BrowseFragmentTestActivity.*;
+
+/**
+ * @hide from javadoc
+ */
public class BrowseTestFragment extends BrowseFragment {
private static final String TAG = "BrowseTestFragment";
@@ -37,23 +42,33 @@ public class BrowseTestFragment extends BrowseFragment {
final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
final static boolean DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD = false;
- static int NUM_ROWS = DEFAULT_NUM_ROWS;
- static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
- static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
- static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
- static boolean SET_ADAPTER_AFTER_DATA_LOAD = DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD;
-
private ArrayObjectAdapter mRowsAdapter;
// For good performance, it's important to use a single instance of
// a card presenter for all rows using that presenter.
final static StringPresenter sCardPresenter = new StringPresenter();
+ int NUM_ROWS;
+ int REPEAT_PER_ROW;
+
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
+ Bundle arguments = getArguments();
+ NUM_ROWS = arguments.getInt(EXTRA_NUM_ROWS, BrowseTestFragment.DEFAULT_NUM_ROWS);
+ REPEAT_PER_ROW = arguments.getInt(EXTRA_REPEAT_PER_ROW,
+ DEFAULT_REPEAT_PER_ROW);
+ long LOAD_DATA_DELAY = arguments.getLong(EXTRA_LOAD_DATA_DELAY,
+ DEFAULT_LOAD_DATA_DELAY);
+ boolean TEST_ENTRANCE_TRANSITION = arguments.getBoolean(
+ EXTRA_TEST_ENTRANCE_TRANSITION,
+ DEFAULT_TEST_ENTRANCE_TRANSITION);
+ final boolean SET_ADAPTER_AFTER_DATA_LOAD = arguments.getBoolean(
+ EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
+ DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
+
if (!SET_ADAPTER_AFTER_DATA_LOAD) {
setupRows();
}
@@ -86,6 +101,9 @@ public class BrowseTestFragment extends BrowseFragment {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
+ if (getActivity() == null || getActivity().isDestroyed()) {
+ return;
+ }
if (SET_ADAPTER_AFTER_DATA_LOAD) {
setupRows();
}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
index 6031dfaaa8..0f9ec2c07c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
@@ -30,6 +30,11 @@ import android.support.v17.leanback.widget.VerticalGridView;
import android.util.Log;
import android.view.View;
+import static android.support.v17.leanback.app.BrowseSupportFragmentTestActivity.*;
+
+/**
+ * @hide from javadoc
+ */
public class BrowseTestSupportFragment extends BrowseSupportFragment {
private static final String TAG = "BrowseTestSupportFragment";
@@ -39,23 +44,33 @@ public class BrowseTestSupportFragment extends BrowseSupportFragment {
final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
final static boolean DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD = false;
- static int NUM_ROWS = DEFAULT_NUM_ROWS;
- static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
- static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
- static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
- static boolean SET_ADAPTER_AFTER_DATA_LOAD = DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD;
-
private ArrayObjectAdapter mRowsAdapter;
// For good performance, it's important to use a single instance of
// a card presenter for all rows using that presenter.
final static StringPresenter sCardPresenter = new StringPresenter();
+ int NUM_ROWS;
+ int REPEAT_PER_ROW;
+
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
+ Bundle arguments = getArguments();
+ NUM_ROWS = arguments.getInt(EXTRA_NUM_ROWS, BrowseTestSupportFragment.DEFAULT_NUM_ROWS);
+ REPEAT_PER_ROW = arguments.getInt(EXTRA_REPEAT_PER_ROW,
+ DEFAULT_REPEAT_PER_ROW);
+ long LOAD_DATA_DELAY = arguments.getLong(EXTRA_LOAD_DATA_DELAY,
+ DEFAULT_LOAD_DATA_DELAY);
+ boolean TEST_ENTRANCE_TRANSITION = arguments.getBoolean(
+ EXTRA_TEST_ENTRANCE_TRANSITION,
+ DEFAULT_TEST_ENTRANCE_TRANSITION);
+ final boolean SET_ADAPTER_AFTER_DATA_LOAD = arguments.getBoolean(
+ EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
+ DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
+
if (!SET_ADAPTER_AFTER_DATA_LOAD) {
setupRows();
}
@@ -88,6 +103,9 @@ public class BrowseTestSupportFragment extends BrowseSupportFragment {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
+ if (getActivity() == null || getActivity().isDestroyed()) {
+ return;
+ }
if (SET_ADAPTER_AFTER_DATA_LOAD) {
setupRows();
}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
index 69e61dca1b..b7cb75dcae 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
@@ -350,4 +350,161 @@ public class PlaybackControlSupportGlueTest {
assertEquals(0, rewind.getIndex());
}
}
+
+ @Test
+ public void testMediaPauseButtonOnFF() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+ PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
+
+ glue.onActionClicked(playPause);
+ glue.onActionClicked(fastForward);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PAUSE));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPauseButtonOnPlay() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+ glue.onActionClicked(playPause);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PAUSE));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPauseButtonOnPause() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+ glue.onActionClicked(playPause);
+ glue.onActionClicked(playPause);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PAUSE));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPlayButtonOnFF() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+ PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
+
+ glue.onActionClicked(playPause);
+ glue.onActionClicked(fastForward);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPlayButtonOnPlay() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+ glue.onActionClicked(playPause);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPlayButtonOnPause() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+ glue.onActionClicked(playPause);
+ glue.onActionClicked(playPause);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPlayPauseButtonOnFF() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+ PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
+
+ glue.onActionClicked(playPause);
+ glue.onActionClicked(fastForward);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPlayPauseButtonOnPlay() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+ glue.onActionClicked(playPause);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ }
+
+ @Test
+ public void testMediaPlayPauseButtonOnPause() {
+ PlaybackControlsRow row = new PlaybackControlsRow();
+ glue.setControlsRow(row);
+ SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+ row.getPrimaryActionsAdapter();
+ PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+ .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+ glue.onActionClicked(playPause);
+ glue.onActionClicked(playPause);
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+ glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+ assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+ }
+
}
diff --git a/v7/appcompat/res/values-es-rUS/strings.xml b/v7/appcompat/res/values-es-rUS/strings.xml
index 9bc27a945f..804941ce4e 100644
--- a/v7/appcompat/res/values-es-rUS/strings.xml
+++ b/v7/appcompat/res/values-es-rUS/strings.xml
@@ -25,7 +25,7 @@
<string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
<string name="abc_searchview_description_search" msgid="8264924765203268293">"Búsqueda"</string>
<string name="abc_search_hint" msgid="7723749260725869598">"Buscar…"</string>
- <string name="abc_searchview_description_query" msgid="2550479030709304392">"Consulta de búsqueda"</string>
+ <string name="abc_searchview_description_query" msgid="2550479030709304392">"Búsqueda"</string>
<string name="abc_searchview_description_clear" msgid="3691816814315814921">"Eliminar la consulta"</string>
<string name="abc_searchview_description_submit" msgid="8928215447528550784">"Enviar consulta"</string>
<string name="abc_searchview_description_voice" msgid="893419373245838918">"Búsqueda por voz"</string>
diff --git a/v7/appcompat/res/values-hy-rAM/strings.xml b/v7/appcompat/res/values-hy-rAM/strings.xml
index c714b9cfaf..dd526113ce 100644
--- a/v7/appcompat/res/values-hy-rAM/strings.xml
+++ b/v7/appcompat/res/values-hy-rAM/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="abc_action_mode_done" msgid="4076576682505996667">"Կատարված է"</string>
+ <string name="abc_action_mode_done" msgid="4076576682505996667">"Պատրաստ է"</string>
<string name="abc_action_bar_home_description" msgid="4600421777120114993">"Ուղղվել տուն"</string>
<string name="abc_action_bar_up_description" msgid="1594238315039666878">"Ուղղվել վերև"</string>
<string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Այլ ընտրանքներ"</string>
diff --git a/v7/appcompat/res/values-kn-rIN/strings.xml b/v7/appcompat/res/values-kn-rIN/strings.xml
index e240f96af3..ce95380cb9 100644
--- a/v7/appcompat/res/values-kn-rIN/strings.xml
+++ b/v7/appcompat/res/values-kn-rIN/strings.xml
@@ -23,7 +23,7 @@
<string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"ಸಂಕುಚಿಸು"</string>
<string name="abc_action_bar_home_description_format" msgid="1397052879051804371">"%1$s, %2$s"</string>
<string name="abc_action_bar_home_subtitle_description_format" msgid="6623331958280229229">"%1$s, %2$s, %3$s"</string>
- <string name="abc_searchview_description_search" msgid="8264924765203268293">"ಹುಡುಕು"</string>
+ <string name="abc_searchview_description_search" msgid="8264924765203268293">"ಹುಡುಕಿ"</string>
<string name="abc_search_hint" msgid="7723749260725869598">"ಹುಡುಕಿ…"</string>
<string name="abc_searchview_description_query" msgid="2550479030709304392">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
<string name="abc_searchview_description_clear" msgid="3691816814315814921">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸು"</string>
@@ -36,5 +36,5 @@
<string name="status_bar_notification_info_overflow" msgid="2869576371154716097">"999+"</string>
<string name="abc_capital_on" msgid="3405795526292276155">"ಆನ್"</string>
<string name="abc_capital_off" msgid="121134116657445385">"ಆಫ್"</string>
- <string name="search_menu_title" msgid="146198913615257606">"ಹುಡುಕು"</string>
+ <string name="search_menu_title" msgid="146198913615257606">"ಹುಡುಕಿ"</string>
</resources>
diff --git a/v7/appcompat/res/values-v11/themes_base.xml b/v7/appcompat/res/values-v11/themes_base.xml
index e0ac24dc21..d38ef32ce0 100644
--- a/v7/appcompat/res/values-v11/themes_base.xml
+++ b/v7/appcompat/res/values-v11/themes_base.xml
@@ -158,4 +158,29 @@
<style name="Base.ThemeOverlay.AppCompat.Dialog" parent="Base.V11.ThemeOverlay.AppCompat.Dialog" />
+ <style name="Base.ThemeOverlay.AppCompat.Dialog.Alert">
+ <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
+ <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
+ </style>
+
+ <style name="Base.Theme.AppCompat.Dialog.Alert">
+ <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
+ <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
+ </style>
+
+ <style name="Base.Theme.AppCompat.Light.Dialog.Alert">
+ <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
+ <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
+ </style>
+
+ <style name="Base.Theme.AppCompat.Dialog.MinWidth">
+ <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
+ <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
+ </style>
+
+ <style name="Base.Theme.AppCompat.Light.Dialog.MinWidth">
+ <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
+ <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
+ </style>
+
</resources>
diff --git a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
index 2ee07d8166..cff87c5507 100644
--- a/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
+++ b/v7/appcompat/src/android/support/v7/view/menu/MenuBuilder.java
@@ -16,6 +16,8 @@
package android.support.v7.view.menu;
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -47,8 +49,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
/**
* Implementation of the {@link android.support.v4.internal.view.SupportMenu} interface for creating a
* standard menu UI.
@@ -165,6 +165,8 @@ public class MenuBuilder implements SupportMenu {
private boolean mItemsChangedWhileDispatchPrevented = false;
+ private boolean mStructureChangedWhileDispatchPrevented = false;
+
private boolean mOptionalIconsVisible = false;
private boolean mIsClosing = false;
@@ -582,6 +584,7 @@ public class MenuBuilder implements SupportMenu {
clearHeader();
mPreventDispatchingItemsChanged = false;
mItemsChangedWhileDispatchPrevented = false;
+ mStructureChangedWhileDispatchPrevented = false;
onItemsChanged(true);
}
@@ -599,6 +602,7 @@ public class MenuBuilder implements SupportMenu {
final int group = item.getGroupId();
final int N = mItems.size();
+ stopDispatchingItemsChanged();
for (int i = 0; i < N; i++) {
MenuItemImpl curItem = mItems.get(i);
if (curItem.getGroupId() == group) {
@@ -609,6 +613,7 @@ public class MenuBuilder implements SupportMenu {
curItem.setCheckedInt(curItem == item);
}
}
+ startDispatchingItemsChanged();
}
@Override
@@ -1042,6 +1047,9 @@ public class MenuBuilder implements SupportMenu {
dispatchPresenterUpdate(structureChanged);
} else {
mItemsChangedWhileDispatchPrevented = true;
+ if (structureChanged) {
+ mStructureChangedWhileDispatchPrevented = true;
+ }
}
}
@@ -1054,6 +1062,7 @@ public class MenuBuilder implements SupportMenu {
if (!mPreventDispatchingItemsChanged) {
mPreventDispatchingItemsChanged = true;
mItemsChangedWhileDispatchPrevented = false;
+ mStructureChangedWhileDispatchPrevented = false;
}
}
@@ -1062,7 +1071,7 @@ public class MenuBuilder implements SupportMenu {
if (mItemsChangedWhileDispatchPrevented) {
mItemsChangedWhileDispatchPrevented = false;
- onItemsChanged(true);
+ onItemsChanged(mStructureChangedWhileDispatchPrevented);
}
}
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
index 09e4a28471..3fffb9f3c9 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatBackgroundHelper.java
@@ -155,10 +155,9 @@ class AppCompatBackgroundHelper {
void applySupportBackgroundTint() {
final Drawable background = mView.getBackground();
if (background != null) {
- if (Build.VERSION.SDK_INT == 21 && applyFrameworkTintUsingColorFilter(background)) {
- // GradientDrawable doesn't implement setTintList on API 21, and since there is
- // no nice way to unwrap DrawableContainers we have to blanket apply this
- // on API 21. This needs to be called before the internal tints below so it takes
+ if (shouldApplyFrameworkTintUsingColorFilter()
+ && applyFrameworkTintUsingColorFilter(background)) {
+ // This needs to be called before the internal tints below so it takes
// effect on any widgets using the compat tint on API 21 (EditText)
return;
}
@@ -186,6 +185,23 @@ class AppCompatBackgroundHelper {
applySupportBackgroundTint();
}
+ private boolean shouldApplyFrameworkTintUsingColorFilter() {
+ final int sdk = Build.VERSION.SDK_INT;
+ if (sdk < 21) {
+ // API 19 and below doesn't have framework tint
+ return false;
+ } else if (sdk == 21) {
+ // GradientDrawable doesn't implement setTintList on API 21, and since there is
+ // no nice way to unwrap DrawableContainers we have to blanket apply this
+ // on API 21
+ return true;
+ } else {
+ // On API 22+, if we're using an internal compat background tint, we're also
+ // responsible for applying any custom tint set via the framework impl
+ return mInternalBackgroundTint != null;
+ }
+ }
+
/**
* Applies the framework background tint to a view, but using the compat method (ColorFilter)
*
diff --git a/v7/appcompat/tests/res/layout/appcompat_button_activity.xml b/v7/appcompat/tests/res/layout/appcompat_button_activity.xml
index 72d6500a3f..7708d0c476 100644
--- a/v7/appcompat/tests/res/layout/appcompat_button_activity.xml
+++ b/v7/appcompat/tests/res/layout/appcompat_button_activity.xml
@@ -76,6 +76,13 @@
android:text="@string/sample_text2"
android:background="@drawable/test_background_green" />
+ <android.support.v7.widget.AppCompatButton
+ android:id="@+id/button_colored_untinted"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/sample_text2"
+ style="@style/Widget.AppCompat.Button.Colored"/>
+
</LinearLayout>
</ScrollView>
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
index 37a3732caf..b68d0efc41 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
@@ -173,6 +173,36 @@ public class TestUtils {
}
/**
+ * Checks whether the center pixel in the specified drawable is of the same specified color.
+ *
+ * In case there is a color mismatch, the behavior of this method depends on the
+ * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
+ * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
+ * <code>Assert.fail</code> with detailed description of the mismatch.
+ */
+ public static void assertCenterPixelOfColor(String failMessagePrefix, @NonNull Drawable drawable,
+ int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
+ int allowedComponentVariance, boolean throwExceptionIfFails) {
+ // Create a bitmap
+ Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
+ // Create a canvas that wraps the bitmap
+ Canvas canvas = new Canvas(bitmap);
+ if (callSetBounds) {
+ // Configure the drawable to have bounds that match the passed size
+ drawable.setBounds(0, 0, drawableWidth, drawableHeight);
+ }
+ // And ask the drawable to draw itself to the canvas / bitmap
+ drawable.draw(canvas);
+
+ try {
+ assertCenterPixelOfColor(failMessagePrefix, bitmap, color, allowedComponentVariance,
+ throwExceptionIfFails);
+ } finally {
+ bitmap.recycle();
+ }
+ }
+
+ /**
* Checks whether the center pixel in the specified bitmap is of the same specified color.
*
* In case there is a color mismatch, the behavior of this method depends on the
@@ -181,8 +211,7 @@ public class TestUtils {
* <code>Assert.fail</code> with detailed description of the mismatch.
*/
public static void assertCenterPixelOfColor(String failMessagePrefix, @NonNull Bitmap bitmap,
- @ColorInt int color,
- int allowedComponentVariance, boolean throwExceptionIfFails) {
+ @ColorInt int color, int allowedComponentVariance, boolean throwExceptionIfFails) {
final int centerX = bitmap.getWidth() / 2;
final int centerY = bitmap.getHeight() / 2;
final @ColorInt int colorAtCenterPixel = bitmap.getPixel(centerX, centerY);
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
index ac10d3b546..3e092c4ab3 100644
--- a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
+++ b/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
@@ -81,6 +81,14 @@ public class TestUtilsMatchers {
* with the specific color.
*/
public static Matcher isBackground(@ColorInt final int color) {
+ return isBackground(color, false);
+ }
+
+ /**
+ * Returns a matcher that matches <code>View</code>s which have background flat-filled
+ * with the specific color.
+ */
+ public static Matcher isBackground(@ColorInt final int color, final boolean onlyTestCenter) {
return new BoundedMatcher<View, View>(View.class) {
private String failedComparisonDescription;
@@ -97,10 +105,14 @@ public class TestUtilsMatchers {
if (drawable == null) {
return false;
}
-
try {
- TestUtils.assertAllPixelsOfColor("", drawable, view.getWidth(),
- view.getHeight(), false, color, 0, true);
+ if (onlyTestCenter) {
+ TestUtils.assertCenterPixelOfColor("", drawable, view.getWidth(),
+ view.getHeight(), false, color, 0, true);
+ } else {
+ TestUtils.assertAllPixelsOfColor("", drawable, view.getWidth(),
+ view.getHeight(), false, color, 0, true);
+ }
// If we are here, the color comparison has passed.
failedComparisonDescription = null;
return true;
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
index 315c12d78a..dca0f2a9c6 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
@@ -15,6 +15,19 @@
*/
package android.support.v7.widget;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.v7.testutils.AppCompatTintableViewActions.setBackgroundResource;
+import static android.support.v7.testutils.AppCompatTintableViewActions.setBackgroundTintList;
+import static android.support.v7.testutils.AppCompatTintableViewActions.setBackgroundTintMode;
+import static android.support.v7.testutils.AppCompatTintableViewActions.setEnabled;
+import static android.support.v7.testutils.TestUtilsActions.setBackgroundTintListViewCompat;
+import static android.support.v7.testutils.TestUtilsActions.setBackgroundTintModeViewCompat;
+import static android.support.v7.testutils.TestUtilsMatchers.isBackground;
+
+import static org.junit.Assert.assertNull;
+
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.PorterDuff;
@@ -29,17 +42,13 @@ import android.support.v7.appcompat.test.R;
import android.support.v7.testutils.AppCompatTintableViewActions;
import android.support.v7.testutils.BaseTestActivity;
import android.support.v7.testutils.TestUtils;
-import android.support.v7.testutils.TestUtilsActions;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import android.view.ViewGroup;
+
import org.junit.Before;
import org.junit.Test;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static org.junit.Assert.assertNull;
-
/**
* Base class for testing custom view extensions in appcompat-v7 that implement the
* <code>TintableBackgroundView</code> interface. Extensions of this class run all tests
@@ -100,11 +109,11 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
assertNull("No background after XML loading", view.getBackground());
// Disable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
assertNull("No background after disabling", view.getBackground());
// Enable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
assertNull("No background after re-enabling", view.getBackground());
// Load a new color state list, set it on the view and check that the background
@@ -112,14 +121,14 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
final ColorStateList sandColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_sand, null);
onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintList(sandColor));
+ setBackgroundTintList(sandColor));
// Disable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
assertNull("No background after disabling", view.getBackground());
// Enable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
assertNull("No background after re-enabling", view.getBackground());
}
@@ -144,26 +153,25 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
assertNull("No background after XML loading", view.getBackground());
// Disable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
assertNull("No background after disabling", view.getBackground());
// Enable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
assertNull("No background after re-enabling", view.getBackground());
// Load a new color state list, set it on the view and check that the background
// is still null.
final ColorStateList lilacColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_lilac, null);
- onView(withId(viewId)).perform(
- TestUtilsActions.setBackgroundTintListViewCompat(lilacColor));
+ onView(withId(viewId)).perform(setBackgroundTintListViewCompat(lilacColor));
// Disable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
assertNull("No background after disabling", view.getBackground());
// Enable the view and check that the background is still null.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
assertNull("No background after re-enabling", view.getBackground());
}
@@ -197,13 +205,13 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// Disable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("Default lilac tinting in disabled state", view,
lilacDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state", view,
lilacDefault, 0);
@@ -212,19 +220,19 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
final ColorStateList sandColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_sand, null);
onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintList(sandColor));
+ setBackgroundTintList(sandColor));
verifyBackgroundIsColoredAs("New sand tinting in enabled state", view,
sandDefault, 0);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New sand tinting in disabled state", view,
sandDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("New sand tinting in re-enabled state", view,
sandDefault, 0);
@@ -232,20 +240,19 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// switched to the matching entry in newly set color state list.
final ColorStateList oceanColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_ocean, null);
- onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintList(oceanColor));
+ onView(withId(viewId)).perform(setBackgroundTintList(oceanColor));
verifyBackgroundIsColoredAs("New ocean tinting in enabled state", view,
oceanDefault, 0);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New ocean tinting in disabled state", view,
oceanDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("New ocean tinting in re-enabled state", view,
oceanDefault, 0);
}
@@ -280,13 +287,13 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// Disable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("Default lilac tinting in disabled state", view,
lilacDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state", view,
lilacDefault, 0);
@@ -294,20 +301,19 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// switched to the matching entry in newly set color state list.
final ColorStateList sandColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_sand, null);
- onView(withId(viewId)).perform(
- TestUtilsActions.setBackgroundTintListViewCompat(sandColor));
+ onView(withId(viewId)).perform(setBackgroundTintListViewCompat(sandColor));
verifyBackgroundIsColoredAs("New sand tinting in enabled state", view,
sandDefault, 0);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New sand tinting in disabled state", view,
sandDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("New sand tinting in re-enabled state", view,
sandDefault, 0);
@@ -316,19 +322,19 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
final ColorStateList oceanColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_ocean, null);
onView(withId(viewId)).perform(
- TestUtilsActions.setBackgroundTintListViewCompat(oceanColor));
+ setBackgroundTintListViewCompat(oceanColor));
verifyBackgroundIsColoredAs("New ocean tinting in enabled state", view,
oceanDefault, 0);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New ocean tinting in disabled state", view,
oceanDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("New ocean tinting in re-enabled state", view,
oceanDefault, 0);
}
@@ -365,21 +371,19 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
final int allowedComponentVariance = 2;
// Set src_in tint mode on our view
- onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintMode(PorterDuff.Mode.SRC_IN));
+ onView(withId(viewId)).perform(setBackgroundTintMode(PorterDuff.Mode.SRC_IN));
// Load a new color state list, set it on the view and check that the background has
// switched to the matching entry in newly set color state list.
final ColorStateList emeraldColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_emerald_translucent, null);
- onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintList(emeraldColor));
+ onView(withId(viewId)).perform(setBackgroundTintList(emeraldColor));
verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_in", view,
emeraldDefault, allowedComponentVariance);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New emerald tinting in disabled state under src_in", view,
emeraldDisabled, allowedComponentVariance);
@@ -387,19 +391,18 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// translucent colors, we expect the actual background of the view to be different under
// this new mode (unlike src_in and src_over that behave identically when the destination is
// a fully filled rectangle and the source is an opaque color).
- onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintMode(PorterDuff.Mode.SRC_OVER));
+ onView(withId(viewId)).perform(setBackgroundTintMode(PorterDuff.Mode.SRC_OVER));
// Enable the view and check that the background has switched to the matching entry
// in the color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_over", view,
ColorUtils.compositeColors(emeraldDefault, backgroundColor),
allowedComponentVariance);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New emerald tinting in disabled state under src_over",
view, ColorUtils.compositeColors(emeraldDisabled, backgroundColor),
allowedComponentVariance);
@@ -437,21 +440,19 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
final int allowedComponentVariance = 2;
// Set src_in tint mode on our view
- onView(withId(viewId)).perform(
- TestUtilsActions.setBackgroundTintModeViewCompat(PorterDuff.Mode.SRC_IN));
+ onView(withId(viewId)).perform(setBackgroundTintModeViewCompat(PorterDuff.Mode.SRC_IN));
// Load a new color state list, set it on the view and check that the background has
// switched to the matching entry in newly set color state list.
final ColorStateList emeraldColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_emerald_translucent, null);
- onView(withId(viewId)).perform(
- TestUtilsActions.setBackgroundTintListViewCompat(emeraldColor));
+ onView(withId(viewId)).perform(setBackgroundTintListViewCompat(emeraldColor));
verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_in", view,
emeraldDefault, allowedComponentVariance);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New emerald tinting in disabled state under src_in", view,
emeraldDisabled, allowedComponentVariance);
@@ -459,19 +460,18 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// translucent colors, we expect the actual background of the view to be different under
// this new mode (unlike src_in and src_over that behave identically when the destination is
// a fully filled rectangle and the source is an opaque color).
- onView(withId(viewId)).perform(
- TestUtilsActions.setBackgroundTintModeViewCompat(PorterDuff.Mode.SRC_OVER));
+ onView(withId(viewId)).perform(setBackgroundTintModeViewCompat(PorterDuff.Mode.SRC_OVER));
// Enable the view and check that the background has switched to the matching entry
// in the color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("New emerald tinting in enabled state under src_over", view,
ColorUtils.compositeColors(emeraldDefault, backgroundColor),
allowedComponentVariance);
// Disable the view and check that the background has switched to the matching entry
// in the newly set color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("New emerald tinting in disabled state under src_over",
view, ColorUtils.compositeColors(emeraldDisabled, backgroundColor),
allowedComponentVariance);
@@ -497,8 +497,7 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
}
// Set background on our view
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setBackgroundDrawable(
- ResourcesCompat.getDrawable(mResources, R.drawable.test_background_green, null)));
+ onView(withId(viewId)).perform(setBackgroundResource(R.drawable.test_background_green));
// Test the default state for tinting set up in the layout XML file.
verifyBackgroundIsColoredAs("Default lilac tinting in enabled state on green background",
@@ -506,13 +505,13 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// Disable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("Default lilac tinting in disabled state on green background",
view, lilacDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state on green background",
view, lilacDefault, 0);
@@ -526,13 +525,13 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// Disable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("Default lilac tinting in disabled state on red background",
view, lilacDisabled, 0);
// Enable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("Default lilac tinting in re-enabled state on red background",
view, lilacDefault, 0);
}
@@ -566,17 +565,15 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// translucent colors, we expect the actual background of the view to be different under
// this new mode (unlike src_in and src_over that behave identically when the destination is
// a fully filled rectangle and the source is an opaque color).
- onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintMode(PorterDuff.Mode.SRC_OVER));
+ onView(withId(viewId)).perform(setBackgroundTintMode(PorterDuff.Mode.SRC_OVER));
// Load and set a translucent color state list as the background tint list
final ColorStateList emeraldColor = ResourcesCompat.getColorStateList(
mResources, R.color.color_state_list_emerald_translucent, null);
onView(withId(viewId)).perform(
- AppCompatTintableViewActions.setBackgroundTintList(emeraldColor));
+ setBackgroundTintList(emeraldColor));
// Set background on our view
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setBackgroundDrawable(
- ResourcesCompat.getDrawable(mResources, R.drawable.test_background_green, null)));
+ onView(withId(viewId)).perform(setBackgroundResource(R.drawable.test_background_green));
// From this point on in this method we're allowing a margin of error in checking the
// color of the view background. This is due to both translucent colors being used
@@ -592,14 +589,14 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// Disable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("Emerald tinting in disabled state on green background",
view, ColorUtils.compositeColors(emeraldDisabled, backgroundColorGreen),
allowedComponentVariance);
// Enable the view and check that the background has switched to the matching entry
// in the default color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("Emerald tinting in re-enabled state on green background",
view, ColorUtils.compositeColors(emeraldDefault, backgroundColorGreen),
allowedComponentVariance);
@@ -615,16 +612,39 @@ public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extend
// Disable the view and check that the background has switched to the matching entry
// in our current color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(false));
+ onView(withId(viewId)).perform(setEnabled(false));
verifyBackgroundIsColoredAs("Emerald tinting in disabled state on red background",
view, ColorUtils.compositeColors(emeraldDisabled, backgroundColorRed),
allowedComponentVariance);
// Enable the view and check that the background has switched to the matching entry
// in our current color state list.
- onView(withId(viewId)).perform(AppCompatTintableViewActions.setEnabled(true));
+ onView(withId(viewId)).perform(setEnabled(true));
verifyBackgroundIsColoredAs("Emerald tinting in re-enabled state on red background",
view, ColorUtils.compositeColors(emeraldDefault, backgroundColorRed),
allowedComponentVariance);
}
+
+ protected void testUntintedBackgroundTintingViewCompatAcrossStateChange(@IdRes int viewId) {
+ final T view = (T) mContainer.findViewById(viewId);
+
+ final @ColorInt int oceanDefault = ResourcesCompat.getColor(
+ mResources, R.color.ocean_default, null);
+ final @ColorInt int oceanDisabled = ResourcesCompat.getColor(
+ mResources, R.color.ocean_disabled, null);
+
+ final ColorStateList oceanColor = ResourcesCompat.getColorStateList(
+ mResources, R.color.color_state_list_ocean, null);
+ onView(withId(viewId)).perform(setBackgroundTintListViewCompat(oceanColor));
+
+ // Disable the view and check that the background has switched to the matching entry
+ // in the newly set color state list.
+ onView(withId(viewId)).perform(setEnabled(false))
+ .check(matches(isBackground(oceanDisabled, true)));
+
+ // Enable the view and check that the background has switched to the matching entry
+ // in the newly set color state list.
+ onView(withId(viewId)).perform(setEnabled(true))
+ .check(matches(isBackground(oceanDefault, true)));
+ }
}
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
index 340737e15c..d3d0a48bcf 100644
--- a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
+++ b/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
@@ -15,16 +15,18 @@
*/
package android.support.v7.widget;
-import android.support.v7.appcompat.test.R;
-import android.support.v7.testutils.TestUtilsActions;
-import android.test.suitebuilder.annotation.SmallTest;
-import org.junit.Test;
-
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.v7.testutils.TestUtilsActions.setTextAppearance;
+
import static org.junit.Assert.assertEquals;
+import android.support.test.filters.SdkSuppress;
+import android.support.v7.appcompat.test.R;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
/**
* In addition to all tinting-related tests done by the base class, this class provides
* tests specific to {@link AppCompatButton} class.
@@ -80,4 +82,13 @@ public class AppCompatButtonTest
assertEquals("Button is not in all caps", text, button.getLayout().getText());
}
+
+ /**
+ * Currently only runs on API 22+ due to http://b.android.com/221469
+ */
+ @Test
+ @SdkSuppress(minSdkVersion = 22)
+ public void testBackgroundTintListOnColoredButton() {
+ testUntintedBackgroundTintingViewCompatAcrossStateChange(R.id.button_colored_untinted);
+ }
}
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
index 8075d2e91a..4bc9baa185 100644
--- a/v7/mediarouter/res/values-b+sr+Latn/strings.xml
+++ b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
@@ -22,7 +22,7 @@
<string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme Prebaci. Veza je prekinuta"</string>
<string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme Prebaci. Povezuje se"</string>
<string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme Prebaci. Povezan je"</string>
- <string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
+ <string name="mr_chooser_title" msgid="414301941546135990">"Prebacuj na"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Pronalaženje uređaja"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
<string name="mr_controller_stop" msgid="4570331844078181931">"Zaustavi prebacivanje"</string>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index 83489ac06e..d6d1888375 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -25,7 +25,7 @@
<string name="mr_chooser_title" msgid="414301941546135990">"Emitir en"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
- <string name="mr_controller_stop" msgid="4570331844078181931">"Parar de emitir"</string>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"Deter emisión"</string>
<string name="mr_controller_close_description" msgid="7333862312480583260">"Pechar"</string>
<string name="mr_controller_play" msgid="683634565969987458">"Reproduce"</string>
<string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index e74967ef55..5b01c7c2da 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -19,12 +19,12 @@
<string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
<string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
<string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट करें बटन"</string>
- <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट करें बटन. डिस्कनेक्ट है"</string>
+ <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट करें बटन. डिसकनेक्ट है"</string>
<string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट करें बटन. कनेक्ट हो रहा है"</string>
<string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट करें बटन. कनेक्ट है"</string>
<string name="mr_chooser_title" msgid="414301941546135990">"इस पर कास्‍ट करें"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"डिवाइस ढूंढ रहा है"</string>
- <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्कनेक्ट करें"</string>
+ <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिसकनेक्ट करें"</string>
<string name="mr_controller_stop" msgid="4570331844078181931">"कास्ट करना बंद करें"</string>
<string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करें"</string>
<string name="mr_controller_play" msgid="683634565969987458">"चलाएं"</string>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
index 258529d00b..c207246430 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -25,7 +25,7 @@
<string name="mr_chooser_title" msgid="414301941546135990">"ਇਸ ਨਾਲ ਕਾਸਟ ਕਰੋ"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"ਡਿਵਾਈਸਾਂ ਲੱਭ ਰਿਹਾ ਹੈ"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
- <string name="mr_controller_stop" msgid="4570331844078181931">"ਜੋੜਨਾ ਰੋਕੋ"</string>
+ <string name="mr_controller_stop" msgid="4570331844078181931">"ਕਾਸਟ ਕਰਨਾ ਰੋਕੋ"</string>
<string name="mr_controller_close_description" msgid="7333862312480583260">"ਬੰਦ ਕਰੋ"</string>
<string name="mr_controller_play" msgid="683634565969987458">"ਪਲੇ ਕਰੋ"</string>
<string name="mr_controller_pause" msgid="5451884435510905406">"ਰੋਕੋ"</string>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index bddc045113..ef1b2b1d57 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -22,7 +22,7 @@
<string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дугме Пребаци. Веза је прекинута"</string>
<string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дугме Пребаци. Повезује се"</string>
<string name="mr_cast_button_connected" msgid="5088427771788648085">"Дугме Пребаци. Повезан је"</string>
- <string name="mr_chooser_title" msgid="414301941546135990">"Пребацујте на"</string>
+ <string name="mr_chooser_title" msgid="414301941546135990">"Пребацуј на"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Проналажење уређаја"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекини везу"</string>
<string name="mr_controller_stop" msgid="4570331844078181931">"Заустави пребацивање"</string>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index c22a91c31e..30c7dcc539 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -30,7 +30,7 @@
<string name="mr_controller_play" msgid="683634565969987458">"播放"</string>
<string name="mr_controller_pause" msgid="5451884435510905406">"暂停"</string>
<string name="mr_controller_expand_group" msgid="8062427022744266907">"展开"</string>
- <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折叠"</string>
+ <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收起"</string>
<string name="mr_controller_album_art" msgid="6422801843540543585">"专辑封面"</string>
<string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑块"</string>
<string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未选择任何媒体"</string>
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
index 9c7747c38f..1e78f94210 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
@@ -503,9 +503,8 @@ final class ColorCutQuantizer {
private static int modifyWordWidth(int value, int currentWidth, int targetWidth) {
final int newValue;
if (targetWidth > currentWidth) {
- // If we're approximating up in word width, we'll use scaling to approximate the
- // new value
- newValue = value * ((1 << targetWidth) - 1) / ((1 << currentWidth) - 1);
+ // If we're approximating up in word width, we'll shift up
+ newValue = value << (targetWidth - currentWidth);
} else {
// Else, we will just shift and keep the MSB
newValue = value >> (currentWidth - targetWidth);
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 46da1b8aa3..b640f79c62 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -453,7 +453,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
* until the end of the layout because a11y service may make sync calls back to the RV while
* the View's state is undefined.
*/
- private final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList();
+ @VisibleForTesting
+ final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList();
private Runnable mItemAnimatorRunner = new Runnable() {
@Override
@@ -1577,6 +1578,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
.hasAnyUpdateTypes(UpdateOp.ADD | UpdateOp.REMOVE | UpdateOp.MOVE)) {
TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
eatRequestLayout();
+ onEnterLayoutOrScroll();
mAdapterHelper.preProcess();
if (!mLayoutRequestEaten) {
if (hasUpdatedView()) {
@@ -1587,6 +1589,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
}
}
resumeRequestLayout(true);
+ onExitLayoutOrScroll();
TraceCompat.endSection();
} else if (mAdapterHelper.hasPendingUpdates()) {
TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
@@ -4493,15 +4496,15 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
public void run() {
try {
TraceCompat.beginSection(TRACE_PREFETCH_TAG);
- final int prefetchCount = mLayout.getItemPrefetchCount();
if (mAdapter == null
|| mLayout == null
|| !mLayout.isItemPrefetchEnabled()
- || prefetchCount < 1
+ || mLayout.getItemPrefetchCount() < 1
|| hasPendingAdapterUpdates()) {
// abort - no work
return;
}
+ final int prefetchCount = mLayout.getItemPrefetchCount();
// Query last vsync so we can predict next one. Note that drawing time not yet
// valid in animation/input callbacks, so query it here to be safe.
@@ -9712,7 +9715,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
private int mWasImportantForAccessibilityBeforeHidden =
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
// set if we defer the accessibility state change of the view holder
- private int mPendingAccessibilityState = PENDING_ACCESSIBILITY_STATE_NOT_SET;
+ @VisibleForTesting
+ int mPendingAccessibilityState = PENDING_ACCESSIBILITY_STATE_NOT_SET;
/**
* Is set when VH is bound from the adapter and cleaned right before it is sent to
@@ -10104,7 +10108,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
for (int i = mPendingAccessibilityImportanceChange.size() - 1; i >= 0; i --) {
ViewHolder viewHolder = mPendingAccessibilityImportanceChange.get(i);
if (viewHolder.itemView.getParent() != this || viewHolder.shouldIgnore()) {
- return;
+ continue;
}
int state = viewHolder.mPendingAccessibilityState;
if (state != ViewHolder.PENDING_ACCESSIBILITY_STATE_NOT_SET) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
index 7ba99a5453..4a7cb27d68 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
@@ -19,18 +19,31 @@ package android.support.v7.widget;
import org.junit.Test;
import org.junit.runner.RunWith;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.view.ViewCompat;
+import android.view.View;
import android.view.ViewGroup;
+import org.mockito.Mockito;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
@RunWith(AndroidJUnit4.class)
public class RecyclerViewAccessibilityLifecycleTest extends BaseRecyclerViewInstrumentationTest {
@Test
@@ -86,6 +99,39 @@ public class RecyclerViewAccessibilityLifecycleTest extends BaseRecyclerViewInst
assertThat(calledA11DuringLayout.get(), is(false));
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ @Test
+ public void processAllViewHolders() {
+ RecyclerView rv = new RecyclerView(getActivity());
+ rv.setLayoutManager(new LinearLayoutManager(getActivity()));
+ View itemView1 = spy(new View(getActivity()));
+ View itemView2 = spy(new View(getActivity()));
+ View itemView3 = spy(new View(getActivity()));
+
+ rv.addView(itemView1);
+ // do not add 2
+ rv.addView(itemView3);
+
+ RecyclerView.ViewHolder vh1 = new RecyclerView.ViewHolder(itemView1) {};
+ vh1.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+ RecyclerView.ViewHolder vh2 = new RecyclerView.ViewHolder(itemView2) {};
+ vh2.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+ RecyclerView.ViewHolder vh3 = new RecyclerView.ViewHolder(itemView3) {};
+ vh3.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+
+ rv.mPendingAccessibilityImportanceChange.add(vh1);
+ rv.mPendingAccessibilityImportanceChange.add(vh2);
+ rv.mPendingAccessibilityImportanceChange.add(vh3);
+ rv.dispatchPendingImportantForAccessibilityChanges();
+
+ verify(itemView1).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ //noinspection WrongConstant
+ verify(itemView2, never()).setImportantForAccessibility(anyInt());
+ verify(itemView3).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ assertThat(rv.mPendingAccessibilityImportanceChange.size(), is(0));
+ }
+
public class LayoutAllLayoutManager extends TestLayoutManager {
private final boolean mAllowNullLayoutLatch;
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 97f9b92676..9166210c05 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
@@ -364,6 +364,12 @@ public class RecyclerViewBasicTest {
assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+ @Test
+ public void prefetcherWithoutLayout() {
+ mRecyclerView.mViewPrefetcher.run();
+ }
+
static class MockLayoutManager extends RecyclerView.LayoutManager {
int mLayoutCount = 0;
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 770ab71ea3..80adf64dfe 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -97,6 +97,64 @@ public class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest
}
@Test
+ public void triggerFocusSearchInOnRecycledCallback() throws Throwable {
+ final RecyclerView rv = new RecyclerView(getActivity()) {
+ @Override
+ void consumePendingUpdateOperations() {
+ try {
+ super.consumePendingUpdateOperations();
+ } catch (Throwable t) {
+ postExceptionToInstrumentation(t);
+ }
+ }
+ };
+ final AtomicBoolean receivedOnRecycled = new AtomicBoolean(false);
+ final TestAdapter adapter = new TestAdapter(20) {
+ @Override
+ public void onViewRecycled(TestViewHolder holder) {
+ super.onViewRecycled(holder);
+ if (receivedOnRecycled.getAndSet(true)) {
+ return;
+ }
+ rv.focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD);
+ }
+ };
+ final AtomicInteger layoutCnt = new AtomicInteger(5);
+ TestLayoutManager tlm = new TestLayoutManager() {
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ detachAndScrapAttachedViews(recycler);
+ layoutRange(recycler, 0, layoutCnt.get());
+ layoutLatch.countDown();
+ }
+ };
+ rv.setLayoutManager(tlm);
+ rv.setAdapter(adapter);
+ tlm.expectLayouts(1);
+ setRecyclerView(rv);
+ tlm.waitForLayout(2);
+
+ layoutCnt.set(4);
+ tlm.expectLayouts(1);
+ requestLayoutOnUIThread(rv);
+ tlm.waitForLayout(1);
+
+ assertThat("test sanity", rv.mRecycler.mCachedViews.size(), is(1));
+ tlm.expectLayouts(1);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ adapter.notifyItemChanged(4);
+ rv.smoothScrollBy(0, 1);
+ }
+ });
+ checkForMainThreadException();
+ tlm.waitForLayout(2);
+ assertThat("test sanity", rv.mRecycler.mCachedViews.size(), is(0));
+ assertThat(receivedOnRecycled.get(), is(true));
+ }
+
+ @Test
public void detachAttachGetReadyWithoutChanges() throws Throwable {
detachAttachGetReady(false, false, false);
}