Merge "MediaBrowser: Handle null results properly in onLoadChildren" into mnc-ub-dev
diff --git a/.gitignore b/.gitignore
index c8c3ed8..a72b3dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@
project.properties
**/bin
**/gen
+*.iml
+**/out
diff --git a/build.gradle b/build.gradle
index e366b16..3b23406 100644
--- a/build.gradle
+++ b/build.gradle
@@ -34,6 +34,7 @@
}
ext.supportRepoOut = new File(buildDir, 'support_repo')
+ext.testApkDistOut = new File(buildDir, 'test_apks')
// Main task called by the build server.
task(createArchive) << {
diff --git a/design/api/current.txt b/design/api/current.txt
index 216100540..7d85b1b 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -375,7 +375,7 @@
method public void setTabMode(int);
method public void setTabTextColors(android.content.res.ColorStateList);
method public void setTabTextColors(int, int);
- method public void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
+ method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
method public void setupWithViewPager(android.support.v4.view.ViewPager);
field public static final int GRAVITY_CENTER = 1; // 0x1
field public static final int GRAVITY_FILL = 0; // 0x0
diff --git a/design/src/android/support/design/widget/DrawableUtils.java b/design/src/android/support/design/widget/DrawableUtils.java
new file mode 100644
index 0000000..1c46e6b2
--- /dev/null
+++ b/design/src/android/support/design/widget/DrawableUtils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.os.Build;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Caution. Gross hacks ahead.
+ */
+class DrawableUtils {
+
+ private static final String LOG_TAG = "DrawableUtils";
+
+ private static Method sSetConstantStateMethod;
+ private static boolean sSetConstantStateMethodFetched;
+
+ private static Field sDrawableContainerStateField;
+ private static boolean sDrawableContainerStateFieldFetched;
+
+ private DrawableUtils() {}
+
+ static boolean setContainerConstantState(DrawableContainer drawable,
+ Drawable.ConstantState constantState) {
+ if (Build.VERSION.SDK_INT >= 9) {
+ // We can use getDeclaredMethod() on v9+
+ return setContainerConstantStateV9(drawable, constantState);
+ } else {
+ // Else we'll just have to set the field directly
+ return setContainerConstantStateV7(drawable, constantState);
+ }
+ }
+
+ private static boolean setContainerConstantStateV9(DrawableContainer drawable,
+ Drawable.ConstantState constantState) {
+ if (!sSetConstantStateMethodFetched) {
+ try {
+ sSetConstantStateMethod = DrawableContainer.class.getDeclaredMethod(
+ "setConstantState", DrawableContainer.DrawableContainerState.class);
+ sSetConstantStateMethod.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ Log.e(LOG_TAG, "Could not fetch setConstantState(). Oh well.");
+ }
+ sSetConstantStateMethodFetched = true;
+ }
+ if (sSetConstantStateMethod != null) {
+ try {
+ sSetConstantStateMethod.invoke(drawable, constantState);
+ return true;
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not invoke setConstantState(). Oh well.");
+ }
+ }
+ return false;
+ }
+
+ private static boolean setContainerConstantStateV7(DrawableContainer drawable,
+ Drawable.ConstantState constantState) {
+ if (!sDrawableContainerStateFieldFetched) {
+ try {
+ sDrawableContainerStateField = DrawableContainer.class
+ .getDeclaredField("mDrawableContainerStateField");
+ sDrawableContainerStateField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ Log.e(LOG_TAG, "Could not fetch mDrawableContainerStateField. Oh well.");
+ }
+ sDrawableContainerStateFieldFetched = true;
+ }
+ if (sDrawableContainerStateField != null) {
+ try {
+ sDrawableContainerStateField.set(drawable, constantState);
+ return true;
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not set mDrawableContainerStateField. Oh well.");
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 5640692..fe1a105 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -21,6 +21,7 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
@@ -33,6 +34,7 @@
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.R;
+import android.support.v4.util.Pools;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewCompat;
@@ -63,6 +65,10 @@
import java.util.ArrayList;
import java.util.Iterator;
+import static android.support.v4.view.ViewPager.SCROLL_STATE_DRAGGING;
+import static android.support.v4.view.ViewPager.SCROLL_STATE_IDLE;
+import static android.support.v4.view.ViewPager.SCROLL_STATE_SETTLING;
+
/**
* TabLayout provides a horizontal layout to display tabs.
*
@@ -81,15 +87,8 @@
* notified when any tab's selection state has been changed.
* <p>
* If you're using a {@link android.support.v4.view.ViewPager} together
- * with this layout, you can use {@link #setTabsFromPagerAdapter(PagerAdapter)} which will populate
- * the tabs using the given {@link PagerAdapter}'s page titles. You should also use a
- * {@link TabLayoutOnPageChangeListener} to forward the scroll and selection changes to this
- * layout like so:
- * <pre>
- * ViewPager viewPager = ...;
- * TabLayout tabLayout = ...;
- * viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(tabLayout));
- * </pre>
+ * with this layout, you can use {@link #setupWithViewPager(ViewPager)} to link the two together.
+ * This layout will be automatically populated from the {@link PagerAdapter}'s page titles.</p>
*
* @see <a href="http://www.google.com/design/spec/components/tabs.html">Tabs</a>
*/
@@ -105,6 +104,8 @@
private static final int ANIMATION_DURATION = 300;
+ private static final Pools.Pool<Tab> sTabPool = new Pools.SynchronizedPool<>(16);
+
/**
* Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab
* labels and a larger number of tabs. They are best used for browsing contexts in touch
@@ -216,6 +217,14 @@
private ValueAnimatorCompat mScrollAnimator;
+ private ViewPager mViewPager;
+ private PagerAdapter mPagerAdapter;
+ private DataSetObserver mPagerAdapterObserver;
+ private TabLayoutOnPageChangeListener mPageChangeListener;
+
+ // Pool we use as a simple RecyclerBin
+ private final Pools.Pool<TabView> mTabViewPool = new Pools.SimplePool<>(12);
+
public TabLayout(Context context) {
this(context, null);
}
@@ -436,7 +445,8 @@
*/
@NonNull
public Tab newTab() {
- return new Tab(this);
+ final Tab poolTab = sTabPool.acquire();
+ return poolTab != null ? poolTab : new Tab(this);
}
/**
@@ -489,9 +499,10 @@
final int selectedTabPosition = mSelectedTab != null ? mSelectedTab.getPosition() : 0;
removeTabViewAt(position);
- Tab removedTab = mTabs.remove(position);
+ final Tab removedTab = mTabs.remove(position);
if (removedTab != null) {
- removedTab.setPosition(Tab.INVALID_POSITION);
+ removedTab.reset();
+ sTabPool.release(removedTab);
}
final int newTabCount = mTabs.size();
@@ -509,12 +520,15 @@
*/
public void removeAllTabs() {
// Remove all the views
- mTabStrip.removeAllViews();
+ for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
+ removeTabViewAt(i);
+ }
- for (Iterator<Tab> i = mTabs.iterator(); i.hasNext(); ) {
- Tab tab = i.next();
- tab.setPosition(Tab.INVALID_POSITION);
+ for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext();) {
+ final Tab tab = i.next();
i.remove();
+ tab.reset();
+ sTabPool.release(tab);
}
mSelectedTab = null;
@@ -600,57 +614,102 @@
/**
* The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
*
- * <p>This method will:
- * <ul>
- * <li>Add a {@link ViewPager.OnPageChangeListener} that will forward events to
- * this TabLayout.</li>
- * <li>Populate the TabLayout's tabs from the ViewPager's {@link PagerAdapter}.</li>
- * <li>Set our {@link TabLayout.OnTabSelectedListener} which will forward
- * selected events to the ViewPager</li>
- * </ul>
- * </p>
+ * <p>This method will link the given ViewPager and this TabLayout together so that any
+ * changes in one are automatically reflected in the other. This includes adapter changes,
+ * scroll state changes, and clicks. The tabs displayed in this layout will be populated
+ * from the ViewPager adapter's page titles.</p>
*
- * @see #setTabsFromPagerAdapter(PagerAdapter)
- * @see TabLayoutOnPageChangeListener
- * @see ViewPagerOnTabSelectedListener
+ * <p>After this method is called, you will not need this method again unless you want
+ * to change the linked ViewPager.</p>
+ *
+ * <p>If the given ViewPager is non-null, it needs to already have a
+ * {@link PagerAdapter} set.</p>
+ *
+ * @param viewPager The ViewPager to link, or {@code null} to clear any previous link.
*/
- public void setupWithViewPager(@NonNull ViewPager viewPager) {
- final PagerAdapter adapter = viewPager.getAdapter();
- if (adapter == null) {
- throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
+ public void setupWithViewPager(@Nullable final ViewPager viewPager) {
+ if (mViewPager != null && mPageChangeListener != null) {
+ // If we've already been setup with a ViewPager, remove us from it
+ mViewPager.removeOnPageChangeListener(mPageChangeListener);
}
- // First we'll add Tabs, using the adapter's page titles
- setTabsFromPagerAdapter(adapter);
-
- // Now we'll add our page change listener to the ViewPager
- viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(this));
-
- // Now we'll add a tab selected listener to set ViewPager's current item
- setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
-
- // Make sure we reflect the currently set ViewPager item
- if (adapter.getCount() > 0) {
- final int curItem = viewPager.getCurrentItem();
- if (getSelectedTabPosition() != curItem) {
- selectTab(getTabAt(curItem));
+ if (viewPager != null) {
+ final PagerAdapter adapter = viewPager.getAdapter();
+ if (adapter == null) {
+ throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
}
+
+ mViewPager = viewPager;
+
+ // Add our custom OnPageChangeListener to the ViewPager
+ if (mPageChangeListener == null) {
+ mPageChangeListener = new TabLayoutOnPageChangeListener(this);
+ }
+ mPageChangeListener.reset();
+ viewPager.addOnPageChangeListener(mPageChangeListener);
+
+ // Now we'll add a tab selected listener to set ViewPager's current item
+ setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
+
+ // Now we'll populate ourselves from the pager adapter
+ setPagerAdapter(adapter, true);
+ } else {
+ // We've been given a null ViewPager so we need to clear out the internal state,
+ // listeners and observers
+ mViewPager = null;
+ setOnTabSelectedListener(null);
+ setPagerAdapter(null, true);
}
}
/**
- * Populate our tab content from the given {@link PagerAdapter}.
- * <p>
- * Any existing tabs will be removed first. Each tab will have it's text set to the value
- * returned from {@link PagerAdapter#getPageTitle(int)}
- * </p>
- *
- * @param adapter the adapter to populate from
+ * @deprecated Use {@link #setupWithViewPager(ViewPager)} to link a TabLayout with a ViewPager
+ * together. When that method is used, the TabLayout will be automatically updated
+ * when the {@link PagerAdapter} is changed.
*/
- public void setTabsFromPagerAdapter(@NonNull PagerAdapter adapter) {
+ @Deprecated
+ public void setTabsFromPagerAdapter(@Nullable final PagerAdapter adapter) {
+ setPagerAdapter(adapter, false);
+ }
+
+ private void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
+ if (mPagerAdapter != null && mPagerAdapterObserver != null) {
+ // If we already have a PagerAdapter, unregister our observer
+ mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
+ }
+
+ mPagerAdapter = adapter;
+
+ if (addObserver && adapter != null) {
+ // Register our observer on the new adapter
+ if (mPagerAdapterObserver == null) {
+ mPagerAdapterObserver = new PagerAdapterObserver();
+ }
+ adapter.registerDataSetObserver(mPagerAdapterObserver);
+ }
+
+ // Finally make sure we reflect the new adapter
+ populateFromPagerAdapter();
+ }
+
+ private void populateFromPagerAdapter() {
removeAllTabs();
- for (int i = 0, count = adapter.getCount(); i < count; i++) {
- addTab(newTab().setText(adapter.getPageTitle(i)));
+
+ if (mPagerAdapter != null) {
+ final int adapterCount = mPagerAdapter.getCount();
+ for (int i = 0; i < adapterCount; i++) {
+ addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
+ }
+
+ // Make sure we reflect the currently set ViewPager item
+ if (mViewPager != null && adapterCount > 0) {
+ final int curItem = mViewPager.getCurrentItem();
+ if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
+ selectTab(getTabAt(curItem));
+ }
+ }
+ } else {
+ removeAllTabs();
}
}
@@ -660,8 +719,12 @@
}
}
- private TabView createTabView(Tab tab) {
- final TabView tabView = new TabView(getContext(), tab);
+ private TabView createTabView(@NonNull final Tab tab) {
+ TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
+ if (tabView == null) {
+ tabView = new TabView(getContext());
+ }
+ tabView.setTab(tab);
tabView.setFocusable(true);
tabView.setMinimumWidth(getTabMinWidth());
@@ -794,7 +857,12 @@
}
private void removeTabViewAt(int position) {
+ final TabView view = (TabView) mTabStrip.getChildAt(position);
mTabStrip.removeViewAt(position);
+ if (view != null) {
+ view.reset();
+ mTabViewPool.release(view);
+ }
requestLayout();
}
@@ -1173,10 +1241,19 @@
public CharSequence getContentDescription() {
return mContentDesc;
}
+
+ private void reset() {
+ mTag = null;
+ mIcon = null;
+ mText = null;
+ mContentDesc = null;
+ mPosition = INVALID_POSITION;
+ mCustomView = null;
+ }
}
class TabView extends LinearLayout implements OnLongClickListener {
- private final Tab mTab;
+ private Tab mTab;
private TextView mTextView;
private ImageView mIconView;
@@ -1186,9 +1263,8 @@
private int mDefaultMaxLines = 2;
- public TabView(Context context, Tab tab) {
+ public TabView(Context context) {
super(context);
- mTab = tab;
if (mTabBackgroundResId != 0) {
setBackgroundDrawable(
AppCompatDrawableManager.get().getDrawable(context, mTabBackgroundResId));
@@ -1197,7 +1273,6 @@
mTabPaddingEnd, mTabPaddingBottom);
setGravity(Gravity.CENTER);
setOrientation(VERTICAL);
- update();
}
@Override
@@ -1297,9 +1372,21 @@
}
}
+ private void setTab(@Nullable final Tab tab) {
+ if (tab != mTab) {
+ mTab = tab;
+ update();
+ }
+ }
+
+ private void reset() {
+ setTab(null);
+ setSelected(false);
+ }
+
final void update() {
final Tab tab = mTab;
- final View custom = tab.getCustomView();
+ final View custom = tab != null ? tab.getCustomView() : null;
if (custom != null) {
final ViewParent customParent = custom.getParent();
if (customParent != this) {
@@ -1351,18 +1438,20 @@
if (mTabTextColors != null) {
mTextView.setTextColor(mTabTextColors);
}
- updateTextAndIcon(tab, mTextView, mIconView);
+ updateTextAndIcon(mTextView, mIconView);
} else {
// Else, we'll see if there is a TextView or ImageView present and update them
if (mCustomTextView != null || mCustomIconView != null) {
- updateTextAndIcon(tab, mCustomTextView, mCustomIconView);
+ updateTextAndIcon(mCustomTextView, mCustomIconView);
}
}
}
- private void updateTextAndIcon(Tab tab, TextView textView, ImageView iconView) {
- final Drawable icon = tab.getIcon();
- final CharSequence text = tab.getText();
+ private void updateTextAndIcon(@Nullable final TextView textView,
+ @Nullable final ImageView iconView) {
+ final Drawable icon = mTab != null ? mTab.getIcon() : null;
+ final CharSequence text = mTab != null ? mTab.getText() : null;
+ final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;
if (iconView != null) {
if (icon != null) {
@@ -1373,20 +1462,20 @@
iconView.setVisibility(GONE);
iconView.setImageDrawable(null);
}
- iconView.setContentDescription(tab.getContentDescription());
+ iconView.setContentDescription(contentDesc);
}
final boolean hasText = !TextUtils.isEmpty(text);
if (textView != null) {
if (hasText) {
textView.setText(text);
- textView.setContentDescription(tab.getContentDescription());
textView.setVisibility(VISIBLE);
setVisibility(VISIBLE);
} else {
textView.setVisibility(GONE);
textView.setText(null);
}
+ textView.setContentDescription(contentDesc);
}
if (iconView != null) {
@@ -1402,7 +1491,7 @@
}
}
- if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) {
+ if (!hasText && !TextUtils.isEmpty(contentDesc)) {
setOnLongClickListener(this);
} else {
setOnLongClickListener(null);
@@ -1751,16 +1840,15 @@
int positionOffsetPixels) {
final TabLayout tabLayout = mTabLayoutRef.get();
if (tabLayout != null) {
- // Update the scroll position, only update the text selection if we're being
- // dragged (or we're settling after a drag)
- final boolean updateText = (mScrollState == ViewPager.SCROLL_STATE_DRAGGING)
- || (mScrollState == ViewPager.SCROLL_STATE_SETTLING
- && mPreviousScrollState == ViewPager.SCROLL_STATE_DRAGGING);
+ // Only update the text selection if we're not settling, or we are settling after
+ // being dragged
+ final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
+ mPreviousScrollState == SCROLL_STATE_DRAGGING;
// Update the indicator if we're not settling after being idle. This is caused
// from a setCurrentItem() call and will be handled by an animation from
// onPageSelected() instead.
- final boolean updateIndicator = !(mScrollState == ViewPager.SCROLL_STATE_SETTLING
- && mPreviousScrollState == ViewPager.SCROLL_STATE_IDLE);
+ final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
+ && mPreviousScrollState == SCROLL_STATE_IDLE);
tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
}
}
@@ -1771,12 +1859,16 @@
if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) {
// Select the tab, only updating the indicator if we're not being dragged/settled
// (since onPageScrolled will handle that).
- final boolean updateIndicator = mScrollState == ViewPager.SCROLL_STATE_IDLE
- || (mScrollState == ViewPager.SCROLL_STATE_SETTLING
- && mPreviousScrollState == ViewPager.SCROLL_STATE_IDLE);
+ final boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
+ || (mScrollState == SCROLL_STATE_SETTLING
+ && mPreviousScrollState == SCROLL_STATE_IDLE);
tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
}
}
+
+ private void reset() {
+ mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
+ }
}
/**
@@ -1806,4 +1898,16 @@
}
}
+ private class PagerAdapterObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ populateFromPagerAdapter();
+ }
+
+ @Override
+ public void onInvalidated() {
+ populateFromPagerAdapter();
+ }
+ }
+
}
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 162643e..318ca6d 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -22,7 +22,10 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
@@ -68,6 +71,7 @@
private Paint mTmpPaint;
private LinearLayout mIndicatorArea;
+ private int mIndicatorsAdded;
private boolean mErrorEnabled;
private TextView mErrorView;
@@ -89,6 +93,8 @@
private boolean mHintAnimationEnabled;
private ValueAnimatorCompat mAnimator;
+ private boolean mHasReconstructedEditTextBackground;
+
public TextInputLayout(Context context) {
this(context, null);
}
@@ -416,6 +422,7 @@
}
mIndicatorArea.setVisibility(View.VISIBLE);
mIndicatorArea.addView(indicator, index);
+ mIndicatorsAdded++;
}
private void adjustIndicatorPadding() {
@@ -427,7 +434,7 @@
private void removeIndicator(TextView indicator) {
if (mIndicatorArea != null) {
mIndicatorArea.removeView(indicator);
- if (mIndicatorArea.getChildCount() == 0) {
+ if (--mIndicatorsAdded == 0) {
mIndicatorArea.setVisibility(View.GONE);
}
}
@@ -624,17 +631,60 @@
}
private void updateEditTextBackground() {
+ ensureBackgroundDrawableStateWorkaround();
+
+ final Drawable editTextBackground = mEditText.getBackground();
+ if (editTextBackground == null) {
+ return;
+ }
+
if (mErrorShown && mErrorView != null) {
- // Set the EditText's background tint to the error color
- ViewCompat.setBackgroundTintList(mEditText,
- ColorStateList.valueOf(mErrorView.getCurrentTextColor()));
+ // Set a color filter of the error color
+ editTextBackground.setColorFilter(
+ AppCompatDrawableManager.getPorterDuffColorFilter(
+ mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
} else if (mCounterOverflowed && mCounterView != null) {
- ViewCompat.setBackgroundTintList(mEditText,
- ColorStateList.valueOf(mCounterView.getCurrentTextColor()));
+ // Set a color filter of the counter color
+ editTextBackground.setColorFilter(
+ AppCompatDrawableManager.getPorterDuffColorFilter(
+ mCounterView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
} else {
- ViewCompat.setBackgroundTintList(mEditText,
- AppCompatDrawableManager.get()
- .getTintList(getContext(), R.drawable.abc_edit_text_material));
+ // Else reset the color filter and refresh the drawable state so that the
+ // normal tint is used
+ editTextBackground.clearColorFilter();
+ mEditText.refreshDrawableState();
+ }
+ }
+
+ private void ensureBackgroundDrawableStateWorkaround() {
+ final Drawable bg = mEditText.getBackground();
+ if (bg == null) {
+ return;
+ }
+
+ if (!mHasReconstructedEditTextBackground) {
+ // This is gross. There is an issue in the platform which affects container Drawables
+ // where the first drawable retrieved from resources will propogate any changes
+ // (like color filter) to all instances from the cache. We'll try to workaround it...
+
+ final Drawable newBg = bg.getConstantState().newDrawable();
+
+ if (bg instanceof DrawableContainer) {
+ // If we have a Drawable container, we can try and set it's constant state via
+ // reflection from the new Drawable
+ mHasReconstructedEditTextBackground =
+ DrawableUtils.setContainerConstantState(
+ (DrawableContainer) bg, newBg.getConstantState());
+ }
+
+ if (!mHasReconstructedEditTextBackground) {
+ // If we reach here then we just need to set a brand new instance of the Drawable
+ // as the background. This has the unfortunate side-effect of wiping out any
+ // user set padding, but I'd hope that use of custom padding on an EditText
+ // is limited.
+ mEditText.setBackgroundDrawable(newBg);
+ mHasReconstructedEditTextBackground = true;
+ }
}
}
diff --git a/design/src/android/support/design/widget/ViewOffsetHelper.java b/design/src/android/support/design/widget/ViewOffsetHelper.java
index a76ca9a..1254f17 100644
--- a/design/src/android/support/design/widget/ViewOffsetHelper.java
+++ b/design/src/android/support/design/widget/ViewOffsetHelper.java
@@ -66,9 +66,9 @@
}
private static void tickleInvalidationFlag(View view) {
- final float x = ViewCompat.getTranslationX(view);
- ViewCompat.setTranslationY(view, x + 1);
- ViewCompat.setTranslationY(view, x);
+ final float y = ViewCompat.getTranslationY(view);
+ ViewCompat.setTranslationY(view, y + 1);
+ ViewCompat.setTranslationY(view, y);
}
/**
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
index 63e93b7..06d8d6f 100644
--- a/graphics/drawable/Android.mk
+++ b/graphics/drawable/Android.mk
@@ -17,8 +17,8 @@
#static vector drawable library
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v7-vectordrawable
-LOCAL_SDK_VERSION := 7
-LOCAL_SRC_FILES := $(call all-java-files-under, static)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, static util)
LOCAL_JAVA_LIBRARIES := android-support-v4
@@ -29,8 +29,8 @@
#Animated vector drawable library
include $(CLEAR_VARS)
LOCAL_MODULE := android-support-v11-animatedvectordrawable
-LOCAL_SDK_VERSION := 11
-LOCAL_SRC_FILES := $(call all-java-files-under, animated)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, animated util)
LOCAL_JAVA_LIBRARIES := android-support-v4
@@ -38,4 +38,5 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-vectordrawable
+LOCAL_AAPT_FLAGS := --no-version-vectors
include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
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 78ef62d..eff9670 100644
--- a/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -16,7 +16,6 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -45,12 +44,12 @@
/**
* This class uses {@link android.animation.ObjectAnimator} and
* {@link android.animation.AnimatorSet} to animate the properties of a
- * {@link android.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
+ * {@link android.support.graphics.drawable.VectorDrawableCompat} to create an animated drawable.
* <p>
* AnimatedVectorDrawableCompat are normally defined as 3 separate XML files.
* </p>
* <p>
- * First is the XML file for {@link android.graphics.drawable.VectorDrawableCompat}. Note that we
+ * First is the XML file for {@link android.support.graphics.drawable.VectorDrawableCompat}. Note that we
* allow the animation to happen on the group's attributes and path's attributes, which requires they
* are uniquely named in this XML file. Groups and paths without animations do not need names.
* </p>
@@ -306,9 +305,9 @@
}
if (ANIMATED_VECTOR.equals(tagName)) {
final TypedArray a =
- obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawable);
+ obtainAttributes(res, theme, attrs, AndroidResources.styleable_AnimatedVectorDrawable);
- int drawableRes = a.getResourceId(R.styleable.AnimatedVectorDrawable_drawable,
+ int drawableRes = a.getResourceId(AndroidResources.styleable_AnimatedVectorDrawable_drawable,
0);
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
Log.v(LOGTAG, "drawableRes is " + drawableRes);
@@ -327,11 +326,11 @@
a.recycle();
} else if (TARGET.equals(tagName)) {
final TypedArray a =
- res.obtainAttributes(attrs, R.styleable.AnimatedVectorDrawableTarget);
+ res.obtainAttributes(attrs, AndroidResources.styleable_AnimatedVectorDrawableTarget);
final String target = a.getString(
- R.styleable.AnimatedVectorDrawableTarget_name);
+ AndroidResources.styleable_AnimatedVectorDrawableTarget_name);
- int id = a.getResourceId(R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+ int id = a.getResourceId(AndroidResources.styleable_AnimatedVectorDrawableTarget_animation, 0);
if (id != 0) {
Animator objectAnimator = AnimatorInflater.loadAnimator(mContext, id);
setupAnimatorsForTarget(target, objectAnimator);
diff --git a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
index a92c3e5..8503fae 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/PathParser.java
@@ -131,8 +131,8 @@
}
for (int i = 0; i < nodesFrom.length; i ++) {
- if (nodesFrom[i].mType != nodesTo[i].mType
- || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+ if (nodesFrom[i].type != nodesTo[i].type
+ || nodesFrom[i].params.length != nodesTo[i].params.length) {
return false;
}
}
@@ -148,9 +148,9 @@
*/
public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
for (int i = 0; i < source.length; i ++) {
- target[i].mType = source[i].mType;
- for (int j = 0; j < source[i].mParams.length; j ++) {
- target[i].mParams[j] = source[i].mParams[j];
+ target[i].type = source[i].type;
+ for (int j = 0; j < source[i].params.length; j ++) {
+ target[i].params[j] = source[i].params[j];
}
}
}
@@ -288,17 +288,18 @@
* An array of PathDataNode can represent the whole "d" attribute.
*/
public static class PathDataNode {
- private char mType;
- private float[] mParams;
+ /*package*/
+ char type;
+ float[] params;
private PathDataNode(char type, float[] params) {
- mType = type;
- mParams = params;
+ this.type = type;
+ this.params = params;
}
private PathDataNode(PathDataNode n) {
- mType = n.mType;
- mParams = copyOfRange(n.mParams, 0, n.mParams.length);
+ type = n.type;
+ params = copyOfRange(n.params, 0, n.params.length);
}
/**
@@ -311,8 +312,8 @@
float[] current = new float[6];
char previousCommand = 'm';
for (int i = 0; i < node.length; i++) {
- addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
- previousCommand = node[i].mType;
+ addCommand(path, current, previousCommand, node[i].type, node[i].params);
+ previousCommand = node[i].type;
}
}
@@ -327,9 +328,9 @@
*/
public void interpolatePathDataNode(PathDataNode nodeFrom,
PathDataNode nodeTo, float fraction) {
- for (int i = 0; i < nodeFrom.mParams.length; i++) {
- mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
- + nodeTo.mParams[i] * fraction;
+ for (int i = 0; i < nodeFrom.params.length; i++) {
+ params[i] = nodeFrom.params[i] * (1 - fraction)
+ + nodeTo.params[i] * fraction;
}
}
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 d33c204..c0e5b40 100644
--- a/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
+++ b/graphics/drawable/static/src/android/support/graphics/drawable/VectorDrawableCompat.java
@@ -196,7 +196,7 @@
private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2;
- private static final boolean DBG_VECTOR_DRAWABLE = true;
+ private static final boolean DBG_VECTOR_DRAWABLE = false;
private VectorDrawableState mVectorState;
@@ -420,7 +420,6 @@
final VectorDrawableCompat drawable = new VectorDrawableCompat();
drawable.inflate(res, parser, attrs, theme);
-
return drawable;
} catch (XmlPullParserException e) {
Log.e(LOGTAG, "parser error", e);
@@ -462,8 +461,9 @@
final VPathRenderer pathRenderer = new VPathRenderer();
state.mVPathRenderer = pathRenderer;
- final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawable);
- updateStateFromTypedArray(a);
+ final TypedArray a = obtainAttributes(res, theme, attrs, AndroidResources.styleable_VectorDrawableTypeArray);
+
+ updateStateFromTypedArray(a, parser);
a.recycle();
state.mChangingConfigurations = getChangingConfigurations();
state.mCacheDirty = true;
@@ -472,30 +472,47 @@
mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
- private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+
+ /**
+ * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
+ * attribute's enum value.
+ */
+ private static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+ switch (value) {
+ case 3: return Mode.SRC_OVER;
+ case 5: return Mode.SRC_IN;
+ case 9: return Mode.SRC_ATOP;
+ case 14: return Mode.MULTIPLY;
+ case 15: return Mode.SCREEN;
+ case 16: return Mode.ADD;
+ default: return defaultMode;
+ }
+ }
+
+ private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) throws XmlPullParserException {
final VectorDrawableState state = mVectorState;
final VPathRenderer pathRenderer = state.mVPathRenderer;
// Account for any configuration changes.
// state.mChangingConfigurations |= Utils.getChangingConfigurations(a);
- final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
- // if (tintMode != -1) {
- // state.mTintMode = Utils.parseTintMode(tintMode, DEFAULT_TINT_MODE);
- // }
+ final int mode = TypedArrayUtils.getNamedInt(a, parser, "tintMode",
+ AndroidResources.styleable_VectorDrawable_Mode, -1);
+ state.mTintMode = parseTintMode(mode, Mode.SRC_IN);
- final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
+ final ColorStateList tint = a.getColorStateList(AndroidResources.styleable_VectorDrawable_tint);
if (tint != null) {
state.mTint = tint;
}
- state.mAutoMirrored = a.getBoolean(
- R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
+ state.mAutoMirrored = TypedArrayUtils.getNamedBoolean(a, parser, "autoMirrored",
+ AndroidResources.styleable_VectorDrawable_autoMirrored, state.mAutoMirrored);
- pathRenderer.mViewportWidth = a.getFloat(
- R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
- pathRenderer.mViewportHeight = a.getFloat(
- R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+ pathRenderer.mViewportWidth = TypedArrayUtils.getNamedFloat(a, parser, "viewportWidth",
+ AndroidResources.styleable_VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
+
+ pathRenderer.mViewportHeight = TypedArrayUtils.getNamedFloat(a, parser, "viewportHeight",
+ AndroidResources.styleable_VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
if (pathRenderer.mViewportWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
@@ -506,10 +523,9 @@
}
pathRenderer.mBaseWidth = a.getDimension(
- R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
+ AndroidResources.styleable_VectorDrawable_width, pathRenderer.mBaseWidth);
pathRenderer.mBaseHeight = a.getDimension(
- R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
-
+ AndroidResources.styleable_VectorDrawable_height, pathRenderer.mBaseHeight);
if (pathRenderer.mBaseWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires width > 0");
@@ -518,11 +534,12 @@
"<vector> tag requires height > 0");
}
- final float alphaInFloat = a.getFloat(R.styleable.VectorDrawable_alpha,
- pathRenderer.getAlpha());
+ // shown up from API 11.
+ final float alphaInFloat = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
+ AndroidResources.styleable_VectorDrawable_alpha, pathRenderer.getAlpha());
pathRenderer.setAlpha(alphaInFloat);
- final String name = a.getString(R.styleable.VectorDrawable_name);
+ final String name = a.getString(AndroidResources.styleable_VectorDrawable_name);
if (name != null) {
pathRenderer.mRootName = name;
pathRenderer.mVGTargetsMap.put(name, pathRenderer);
@@ -545,10 +562,9 @@
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
final VGroup currentGroup = groupStack.peek();
- Log.v(LOGTAG, tagName);
if (SHAPE_PATH.equals(tagName)) {
final VFullPath path = new VFullPath();
- path.inflate(res, attrs, theme);
+ path.inflate(res, attrs, theme, parser);
currentGroup.mChildren.add(path);
if (path.getPathName() != null) {
pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
@@ -557,7 +573,7 @@
state.mChangingConfigurations |= path.mChangingConfigurations;
} else if (SHAPE_CLIP_PATH.equals(tagName)) {
final VClipPath path = new VClipPath();
- path.inflate(res, attrs, theme);
+ path.inflate(res, attrs, theme, parser);
currentGroup.mChildren.add(path);
if (path.getPathName() != null) {
pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
@@ -565,7 +581,7 @@
state.mChangingConfigurations |= path.mChangingConfigurations;
} else if (SHAPE_GROUP.equals(tagName)) {
VGroup newChildGroup = new VGroup();
- newChildGroup.inflate(res, attrs, theme);
+ newChildGroup.inflate(res, attrs, theme, parser);
currentGroup.mChildren.add(newChildGroup);
groupStack.push(newChildGroup);
if (newChildGroup.getGroupName() != null) {
@@ -614,6 +630,8 @@
Object child = currentGroup.mChildren.get(i);
if (child instanceof VGroup) {
printGroupTree((VGroup) child, level + 1);
+ } else {
+ ((VPath) child).printVPath(level + 1);
}
}
}
@@ -1017,29 +1035,41 @@
return mLocalMatrix;
}
- public void inflate(Resources res, AttributeSet attrs, Theme theme) {
+ public void inflate(Resources res, AttributeSet attrs, Theme theme, XmlPullParser parser) {
final TypedArray a = obtainAttributes(res, theme, attrs,
- R.styleable.VectorDrawableGroup);
- updateStateFromTypedArray(a);
+ AndroidResources.styleable_VectorDrawableGroup);
+ updateStateFromTypedArray(a, parser);
a.recycle();
}
- private void updateStateFromTypedArray(TypedArray a) {
+ private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) {
// Account for any configuration changes.
// mChangingConfigurations |= Utils.getChangingConfigurations(a);
// Extract the theme attributes, if any.
mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
- mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
- mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
- mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
- mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
- mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
- mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
- mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+ // This is added in API 11
+ mRotate = TypedArrayUtils.getNamedFloat(a, parser, "rotation",
+ AndroidResources.styleable_VectorDrawableGroup_rotation, mRotate);
- final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
+ mPivotX = a.getFloat(AndroidResources.styleable_VectorDrawableGroup_pivotX, mPivotX);
+ mPivotY = a.getFloat(AndroidResources.styleable_VectorDrawableGroup_pivotY, mPivotY);
+
+ // This is added in API 11
+ mScaleX = TypedArrayUtils.getNamedFloat(a, parser, "scaleX",
+ AndroidResources.styleable_VectorDrawableGroup_scaleX, mScaleX);
+
+ // This is added in API 11
+ mScaleY = TypedArrayUtils.getNamedFloat(a, parser, "scaleY",
+ AndroidResources.styleable_VectorDrawableGroup_scaleY, mScaleY);
+
+ mTranslateX = TypedArrayUtils.getNamedFloat(a, parser, "translateX",
+ AndroidResources.styleable_VectorDrawableGroup_translateX, mTranslateX);
+ mTranslateY = TypedArrayUtils.getNamedFloat(a, parser, "translateY",
+ AndroidResources.styleable_VectorDrawableGroup_translateY, mTranslateY);
+
+ final String groupName = a.getString(AndroidResources.styleable_VectorDrawableGroup_name);
if (groupName != null) {
mGroupName = groupName;
}
@@ -1162,6 +1192,28 @@
// Empty constructor.
}
+ public void printVPath(int level) {
+ String indent = "";
+ for (int i = 0; i < level; i++) {
+ indent += " ";
+ }
+ Log.v(LOGTAG, indent + "current path is :" + mPathName +
+ " pathData is " + NodesToString(mNodes));
+
+ }
+
+ public String NodesToString(PathParser.PathDataNode[] nodes) {
+ String result = " ";
+ for (int i = 0; i < nodes.length; i++) {
+ result += nodes[i].type + ":";
+ float[] params = nodes[i].params;
+ for (int j = 0; j < params.length; j++) {
+ result += params[j] + ",";
+ }
+ }
+ return result;
+ }
+
public VPath(VPath copy) {
mPathName = copy.mPathName;
mChangingConfigurations = copy.mChangingConfigurations;
@@ -1219,10 +1271,14 @@
super(copy);
}
- public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ public void inflate(Resources r, AttributeSet attrs, Theme theme, XmlPullParser parser) {
// TODO TINT THEME Not supported yet
+ final boolean hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData");
+ if (!hasPathData) {
+ return;
+ }
final TypedArray a = obtainAttributes(r, theme, attrs,
- R.styleable.VectorDrawableClipPath);
+ AndroidResources.styleable_VectorDrawableClipPath);
updateStateFromTypedArray(a);
a.recycle();
}
@@ -1231,12 +1287,12 @@
// Account for any configuration changes.
// mChangingConfigurations |= Utils.getChangingConfigurations(a);;
- final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+ final String pathName = a.getString(AndroidResources.styleable_VectorDrawableClipPath_name);
if (pathName != null) {
mPathName = pathName;
}
- final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+ final String pathData = a.getString(AndroidResources.styleable_VectorDrawableClipPath_pathData);
if (pathData != null) {
mNodes = PathParser.createNodesFromPathData(pathData);
}
@@ -1325,52 +1381,64 @@
return mThemeAttrs != null;
}
- public void inflate(Resources r, AttributeSet attrs, Theme theme) {
+ public void inflate(Resources r, AttributeSet attrs, Theme theme, XmlPullParser parser) {
final TypedArray a = obtainAttributes(r, theme, attrs,
- R.styleable.VectorDrawablePath);
- updateStateFromTypedArray(a);
+ AndroidResources.styleable_VectorDrawablePath);
+ updateStateFromTypedArray(a, parser);
a.recycle();
}
- private void updateStateFromTypedArray(TypedArray a) {
+ private void updateStateFromTypedArray(TypedArray a, XmlPullParser parser) {
// Account for any configuration changes.
// mChangingConfigurations |= Utils.getChangingConfigurations(a);
// Extract the theme attributes, if any.
mThemeAttrs = null; // TODO TINT THEME Not supported yet a.extractThemeAttrs();
- final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+ // In order to work around the conflicting id issue, we need to double check the existence
+ // of the attribute.
+ // B/c if the attribute existed in the compiled XML, then calling TypedArray will be safe
+ // since the framework will look up in the XML first.
+ // Note that each getAttributeValue take roughly 0.03ms, it is a price we have to pay here.
+ final boolean hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData");
+ if (!hasPathData) {
+ //If there is no pathData in the <path> tag, then this is an empty path, nothing need to be drawn.
+ return;
+ }
+
+ final String pathName = a.getString(AndroidResources.styleable_VectorDrawablePath_name);
if (pathName != null) {
mPathName = pathName;
}
-
- final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+ final String pathData = a.getString(AndroidResources.styleable_VectorDrawablePath_pathData);
if (pathData != null) {
mNodes = PathParser.createNodesFromPathData(pathData);
}
- mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
- mFillColor);
- mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha,
- mFillAlpha);
- mStrokeLineCap = getStrokeLineCap(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
- mStrokeLineJoin = getStrokeLineJoin(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
- mStrokeMiterlimit = a.getFloat(
- R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
- mStrokeColor = a.getColor(R.styleable.VectorDrawablePath_strokeColor,
- mStrokeColor);
- mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
- mStrokeAlpha);
- mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
- mStrokeWidth);
- mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
- mTrimPathEnd);
- mTrimPathOffset = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
- mTrimPathStart = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+ mFillColor = TypedArrayUtils.getNamedColor(a, parser, "fillColor",
+ AndroidResources.styleable_VectorDrawablePath_fillColor, mFillColor);
+ mFillAlpha = TypedArrayUtils.getNamedFloat(a, parser, "alpha",
+ AndroidResources.styleable_VectorDrawablePath_fillAlpha, mFillAlpha);
+ final int lineCap = TypedArrayUtils.getNamedInt(a, parser, "strokeLineCap",
+ AndroidResources.styleable_VectorDrawablePath_strokeLineCap, -1);
+ mStrokeLineCap = getStrokeLineCap(lineCap, mStrokeLineCap);
+ final int lineJoin = TypedArrayUtils.getNamedInt(a, parser, "strokeLineJoin",
+ AndroidResources.styleable_VectorDrawablePath_strokeLineJoin, -1);
+ mStrokeLineJoin = getStrokeLineJoin(lineJoin, mStrokeLineJoin);
+ mStrokeMiterlimit = TypedArrayUtils.getNamedFloat(a, parser, "strokeMiterLimit",
+ AndroidResources.styleable_VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
+ mStrokeColor = TypedArrayUtils.getNamedColor(a, parser, "strokeColor",
+ AndroidResources.styleable_VectorDrawablePath_strokeColor, mStrokeColor);
+ mStrokeAlpha = TypedArrayUtils.getNamedFloat(a, parser, "strokeAlpha",
+ AndroidResources.styleable_VectorDrawablePath_strokeAlpha, mStrokeAlpha);
+ mStrokeWidth = TypedArrayUtils.getNamedFloat(a, parser, "strokeWidth",
+ AndroidResources.styleable_VectorDrawablePath_strokeWidth, mStrokeWidth);
+ mTrimPathEnd = TypedArrayUtils.getNamedFloat(a, parser, "trimPathEnd",
+ AndroidResources.styleable_VectorDrawablePath_trimPathEnd, mTrimPathEnd);
+ mTrimPathOffset = TypedArrayUtils.getNamedFloat(a, parser, "trimPathOffset",
+ AndroidResources.styleable_VectorDrawablePath_trimPathOffset, mTrimPathOffset);
+ mTrimPathStart = TypedArrayUtils.getNamedFloat(a, parser, "trimPathStart",
+ AndroidResources.styleable_VectorDrawablePath_trimPathStart, mTrimPathStart);
}
@Override
@@ -1381,7 +1449,7 @@
/*
* TODO TINT THEME Not supported yet final TypedArray a =
- * t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+ * t.resolveAttributes(mThemeAttrs, styleable_VectorDrawablePath);
* updateStateFromTypedArray(a); a.recycle();
*/
}
diff --git a/graphics/drawable/testanimated/Android.mk b/graphics/drawable/testanimated/Android.mk
index c888d9e..004cddb 100644
--- a/graphics/drawable/testanimated/Android.mk
+++ b/graphics/drawable/testanimated/Android.mk
@@ -18,7 +18,7 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 11
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -30,6 +30,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v11-animatedvectordrawable android-support-v4
-LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages android.support.graphics.drawable
+LOCAL_AAPT_FLAGS += --auto-add-overlay \
+ --extra-packages android.support.graphics.drawable \
+ --no-version-vectors
include $(BUILD_PACKAGE)
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
index 7c3b1de..dac981b 100644
--- a/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_drawable_grouping_1.xml
@@ -14,14 +14,13 @@
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:drawable="@drawable/vector_drawable_grouping_1" >
+ android:drawable="@drawable/vector_drawable_grouping_1" >
<target
- auto:name="sun"
- auto:animation="@anim/animation_grouping_1_01" />
+ android:name="sun"
+ android:animation="@anim/animation_grouping_1_01" />
<target
- auto:name="earth"
- auto:animation="@anim/animation_grouping_1_01" />
+ android:name="earth"
+ android:animation="@anim/animation_grouping_1_01" />
</animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
index e37d2a1..2944dc2 100644
--- a/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
+++ b/graphics/drawable/testanimated/res/drawable/animation_vector_progress_bar.xml
@@ -14,13 +14,12 @@
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:drawable="@drawable/vector_drawable_progress_bar" >
+ android:drawable="@drawable/vector_drawable_progress_bar" >
<target
- auto:name="pie1"
- auto:animation="@anim/trim_path_animation_progress_bar" />
+ android:name="pie1"
+ android:animation="@anim/trim_path_animation_progress_bar" />
<target
- auto:name="root_bar"
- auto:animation="@anim/alpha_animation_progress_bar" />
+ android:name="root_bar"
+ android:animation="@anim/alpha_animation_progress_bar" />
</animated-vector>
\ No newline at end of file
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
index eceda71..06f098e 100644
--- a/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_grouping_1.xml
@@ -14,37 +14,36 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="256"
- auto:viewportWidth="256" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="256"
+ android:viewportWidth="256" >
<group
- auto:name="shape_layer_1"
- auto:translateX="128"
- auto:translateY="128" >
- <group auto:name="sun" >
+ android:name="shape_layer_1"
+ android:translateX="128"
+ android:translateY="128" >
+ <group android:name="sun" >
<path
- auto:name="ellipse_path_1"
- auto:fillColor="#ffff8000"
- auto:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
+ android:name="ellipse_path_1"
+ android:fillColor="#ffff8000"
+ android:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" />
<group
- auto:name="earth"
- auto:translateX="75" >
+ android:name="earth"
+ android:translateX="75" >
<path
- auto:name="ellipse_path_1_1"
- auto:fillColor="#ff5656ea"
- auto:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
+ android:name="ellipse_path_1_1"
+ android:fillColor="#ff5656ea"
+ android:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" />
<group
- auto:name="moon"
- auto:translateX="25" >
+ android:name="moon"
+ android:translateX="25" >
<path
- auto:name="ellipse_path_1_2"
- auto:fillColor="#ffadadad"
- auto:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
+ android:name="ellipse_path_1_2"
+ android:fillColor="#ffadadad"
+ android:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" />
</group>
</group>
</group>
diff --git a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
index 0b8884b..535265e 100644
--- a/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
+++ b/graphics/drawable/testanimated/res/drawable/vector_drawable_progress_bar.xml
@@ -14,36 +14,35 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="64"
- auto:viewportWidth="64"
- auto:name="root_bar" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="64"
+ android:viewportWidth="64"
+ android:name="root_bar" >
<group
- auto:name="root"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="0"
- auto:translateX="32.0"
- auto:translateY="32.0" >
+ android:name="root"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="0"
+ android:translateX="32.0"
+ android:translateY="32.0" >
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="0" >
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="0" >
<path
- auto:name="pie1"
- auto:fillColor="#00000000"
- auto:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
- auto:strokeColor="#FF00FFFF"
- auto:strokeLineCap="round"
- auto:strokeLineJoin="miter"
- auto:strokeWidth="2"
- auto:trimPathEnd="0.1"
- auto:trimPathOffset="0"
- auto:trimPathStart="0" />
+ android:name="pie1"
+ android:fillColor="#00000000"
+ android:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19"
+ android:strokeColor="#FF00FFFF"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="miter"
+ android:strokeWidth="2"
+ android:trimPathEnd="0.1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
</group>
diff --git a/graphics/drawable/teststatic/Android.mk b/graphics/drawable/teststatic/Android.mk
index d8a0fd7..4c4a7ba 100644
--- a/graphics/drawable/teststatic/Android.mk
+++ b/graphics/drawable/teststatic/Android.mk
@@ -18,7 +18,7 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := 7
+LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -32,7 +32,8 @@
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
- --extra-packages android.support.graphics.drawable
+ --extra-packages android.support.graphics.drawable \
+ --no-version-vectors
include $(BUILD_PACKAGE)
diff --git a/graphics/drawable/teststatic/AndroidManifest.xml b/graphics/drawable/teststatic/AndroidManifest.xml
index 19586fb..39ac8ba 100644
--- a/graphics/drawable/teststatic/AndroidManifest.xml
+++ b/graphics/drawable/teststatic/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.support.test.vectordrawable" >
- <uses-sdk android:minSdkVersion="7" />
+ <uses-sdk android:minSdkVersion="7"/>
<application android:icon="@drawable/app_sample_code" android:label="VectorDrawableCompatTest" >
<activity android:name="android.support.test.vectordrawable.TestActivity" />
@@ -29,4 +29,4 @@
</intent-filter>
</application>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
index 12357ef..286b487 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable01.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
@@ -15,20 +14,16 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="48dp"
- auto:viewportHeight="480"
- auto:viewportWidth="480"
- auto:width="48dp" >
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="480"
+ android:viewportWidth="480" >
<group>
<path
- auto:name="box1"
- auto:fillColor="?android:attr/textColorPrimary"
- auto:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
- auto:strokeColor="?android:attr/colorBackground"
- auto:strokeLineCap="round"
- auto:strokeLineJoin="round" />
+ android:name="box1"
+ android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round" />
</group>
-
-</vector>
\ No newline at end of file
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
index cb6b9df..7567887 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable02.xml
@@ -1,5 +1,4 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,24 +13,20 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="320"
- auto:viewportWidth="320"
- auto:width="64dp" >
-
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="320"
+ android:viewportHeight="320">
<group
- auto:pivotX="70"
- auto:pivotY="120"
- auto:rotation="180" >
+ android:rotation="180"
+ android:pivotX="70"
+ android:pivotY="120">
<path
- auto:name="house"
- auto:fillColor="#ff440000"
- auto:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10"
- auto:trimPathEnd=".9"
- auto:trimPathStart=".1" />
+ android:name="house"
+ android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
+ android:fillColor="#ff440000"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10"
+ android:trimPathStart=".1"
+ android:trimPathEnd=".9"/>
</group>
-
-</vector>
\ No newline at end of file
+</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
index 37d0086..454468a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable03.xml
@@ -14,51 +14,57 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="12.25"
- auto:viewportWidth="7.30625"
- auto:width="64dp" >
+ android:height="64dp"
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625"
+ android:width="64dp" >
<group
- auto:pivotX="3.65"
- auto:pivotY="6.125"
- auto:rotation="-30" >
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="-30" >
<clip-path
- auto:name="clip1"
- auto:pathData="
+ android:name="clip1"
+ android:pathData="
M 0, 6.125
l 7.3, 0
l 0, 12.25
l-7.3, 0
z" />
- </group>
- <group>
- <path
- auto:name="one"
- auto:fillColor="#ff88ff"
- auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+
+ <group
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="30" >
+ <path
+ android:name="one"
+ android:fillColor="#ff88ff"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
l-5.046875,0.0 0.0-1.0Z" />
+ </group>
</group>
<group
- auto:pivotX="3.65"
- auto:pivotY="6.125"
- auto:rotation="-30" >
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="-30" >
<clip-path
- auto:name="clip2"
- auto:pathData="
+ android:name="clip2"
+ android:pathData="
M 0, 0
l 7.3, 0
l 0, 6.125
l-7.3, 0
z" />
- </group>
- <group>
- <path
- auto:name="two"
- auto:fillColor="#ff88ff"
- auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+
+ <group
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="30" >
+ <path
+ android:name="two"
+ android:fillColor="#ff88ff"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -67,6 +73,7 @@
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
q-0.78125024,0.8125-2.2187502,2.265625Z" />
+ </group>
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
index 4e2086f..e6658a6 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable04.xml
@@ -13,38 +13,41 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp"
- auto:viewportWidth="7.30625"
- auto:viewportHeight="12.25"
- auto:autoMirrored="true">
+ android:autoMirrored="true"
+ android:height="64dp"
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625"
+ android:width="64dp" >
<group>
<clip-path
- auto:name="clip1"
- auto:pathData="
+ android:name="clip1"
+ android:pathData="
M 3.65, 6.125
m-.001, 0
a .001,.001 0 1,0 .002,0
- a .001,.001 0 1,0-.002,0z"/>
- <path
- auto:name="one"
- auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
- l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l-5.046875,0.0 0.0-1.0Z"
- auto:fillColor="#ff88ff"/>
+ a .001,.001 0 1,0-.002,0z" />
+ <path
+ android:name="one"
+ android:fillColor="#ff88ff"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
+ l-5.046875,0.0 0.0-1.0Z" />
+ </group>
+ <group>
<clip-path
- auto:name="clip2"
- auto:pathData="
+ android:name="clip2"
+ android:pathData="
M 3.65, 6.125
m-6, 0
a 6,6 0 1,0 12,0
- a 6,6 0 1,0-12,0z"/>
+ a 6,6 0 1,0-12,0z" />
+
<path
- auto:name="two"
- auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ android:name="two"
+ android:fillColor="#ff88ff"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
@@ -52,7 +55,7 @@
q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625
q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375
- q-0.78125024,0.8125-2.2187502,2.265625Z"
- auto:fillColor="#ff88ff"/>
+ q-0.78125024,0.8125-2.2187502,2.265625Z" />
</group>
-</vector>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
index 48801e3..d1723dc 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable05.xml
@@ -14,24 +14,23 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="12.25"
- auto:viewportWidth="7.30625" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625" >
<group>
<path
- auto:name="one"
- auto:fillColor="#ffff00"
- auto:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
+ android:name="one"
+ android:fillColor="#ffff00"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125
l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
l-5.046875,0.0 0.0-1.0Z" />
<path
- auto:name="two"
- auto:fillColor="#ffff00"
- auto:fillAlpha="0"
- auto:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
+ android:name="two"
+ android:fillColor="#ffff00"
+ android:fillAlpha="0"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375
q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625
q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625
q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
index 24173e2..4b530fd 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable06.xml
@@ -13,37 +13,36 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp"
- auto:viewportWidth="700"
- auto:viewportHeight="700">
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="700"
+ android:viewportHeight="700">
<group>
- <path auto:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
- auto:name="path2451"
- auto:fillColor="#00000000"
- auto:strokeColor="#FF000000"
- auto:strokeWidth="30.65500000000000"/>
- <path auto:pathData="M 365.015 311.066"
- auto:name="path2453"
- auto:fillColor="#00000000"
- auto:strokeColor="#FF000000"
- auto:strokeWidth="30.655000000000001"/>
- <path auto:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
- auto:name="path2455"
- auto:strokeColor="#FF000000"
- auto:fillColor="#FFFFFFFF"
- auto:strokeWidth="30.655000000000001"/>
- <path auto:pathData="M 170.515 451.566L 305.61 313.46"
- auto:name="path2457"
- auto:fillColor="#00000000"
- auto:strokeColor="#000000"
- auto:strokeWidth="30.655000000000001"/>
- <path auto:pathData="M 557.968 449.974L 426.515 315.375"
- auto:name="path2459"
- auto:fillColor="#00000000"
- auto:strokeColor="#000000"
- auto:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
+ android:name="path2451"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="30.65500000000000"/>
+ <path android:pathData="M 365.015 311.066"
+ android:name="path2453"
+ android:fillColor="#00000000"
+ android:strokeColor="#FF000000"
+ android:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
+ android:name="path2455"
+ android:strokeColor="#FF000000"
+ android:fillColor="#FFFFFFFF"
+ android:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 170.515 451.566L 305.61 313.46"
+ android:name="path2457"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeWidth="30.655000000000001"/>
+ <path android:pathData="M 557.968 449.974L 426.515 315.375"
+ android:name="path2459"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeWidth="30.655000000000001"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
index 90435d3..bbf2451 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable07.xml
@@ -13,18 +13,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp" auto:viewportWidth="140"
- auto:viewportHeight="110">
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="140"
+ android:viewportHeight="110">
<group>
<path
- auto:name="back"
- auto:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
+ android:name="back"
+ android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z
M 27,50 l 97,0 0,10-97,0 z
M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z"
- auto:fillColor="#ffffffff"
+ android:fillColor="#ffffffff"
/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
index 251d694..e5b59df 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable08.xml
@@ -13,18 +13,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp" auto:viewportWidth="600"
- auto:viewportHeight="600">
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="600"
+ android:viewportHeight="600">
<group>
<path
- auto:name="pie1"
- auto:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
- auto:fillColor="#ffffcc00"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="1"/>
+ android:name="pie1"
+ android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
+ android:fillColor="#ffffcc00"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="1"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
index eccb0d0..ce2441d 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable09.xml
@@ -14,20 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200" >
<group
- auto:pivotX="100"
- auto:pivotY="100"
- auto:rotation="90">
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90">
<path
- auto:name="house"
- auto:fillColor="#ffffffff"
- auto:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
+ android:name="house"
+ android:fillColor="#ffffffff"
+ android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/>
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
index b26d30d..935d4a5 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable10.xml
@@ -15,29 +15,28 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportWidth="200"
- auto:viewportHeight="200">
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportWidth="200"
+ android:viewportHeight="200">
<group>
<path
- auto:name="bar3"
- auto:fillColor="#FFFFFFFF"
- auto:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
+ android:name="bar3"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" />
<path
- auto:name="bar2"
- auto:fillColor="#FFFFFFFF"
- auto:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+ android:name="bar2"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
- auto:name="bar1"
- auto:fillColor="#FF555555"
- auto:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+ android:name="bar1"
+ android:fillColor="#FF555555"
+ android:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
<path
- auto:name="bar0"
- auto:fillColor="#FF555555"
- auto:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
+ android:name="bar0"
+ android:fillColor="#FF555555"
+ android:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
index eb440f5..05f481b 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable11.xml
@@ -14,23 +14,22 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="80"
- auto:viewportWidth="40" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="80"
+ android:viewportWidth="40" >
<group>
<path
- auto:name="battery"
- auto:fillColor="#3388ff"
- auto:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
- auto:strokeColor="#ff8833"
- auto:strokeWidth="1" />
+ android:name="battery"
+ android:fillColor="#3388ff"
+ android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+ android:strokeColor="#ff8833"
+ android:strokeWidth="1" />
<path
- auto:name="spark"
- auto:fillColor="#FFFF0000"
- auto:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
+ android:name="spark"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
index 94a23e8..94338a7 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable12.xml
@@ -14,79 +14,78 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:name="rootGroup"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="600"
- auto:viewportWidth="600"
- auto:alpha="0.5" >
+ android:name="rootGroup"
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="600"
+ android:viewportWidth="600"
+ android:alpha="0.5" >
<group
- auto:name="rotationGroup"
- auto:pivotX="300.0"
- auto:pivotY="300.0"
- auto:rotation="45.0" >
+ android:name="rotationGroup"
+ android:pivotX="300.0"
+ android:pivotY="300.0"
+ android:rotation="45.0" >
<path
- auto:name="pie1"
- auto:fillColor="#00000000"
- auto:pathData="M300,70 a230,230 0 1,0 1,0 z"
- auto:strokeColor="#FF777777"
- auto:strokeWidth="70"
- auto:trimPathEnd=".75"
- auto:trimPathOffset="0"
- auto:trimPathStart="0" />
+ android:name="pie1"
+ android:fillColor="#00000000"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:strokeColor="#FF777777"
+ android:strokeWidth="70"
+ android:trimPathEnd=".75"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
<path
- auto:name="v"
- auto:fillColor="#000000"
- auto:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
+ android:name="v"
+ android:fillColor="#000000"
+ android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
<group
- auto:name="translateToCenterGroup"
- auto:rotation="0.0"
- auto:translateX="200.0"
- auto:translateY="200.0" >
+ android:name="translateToCenterGroup"
+ android:rotation="0.0"
+ android:translateX="200.0"
+ android:translateY="200.0" >
<group
- auto:name="rotationGroup2"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup2"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines1"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroupHalf"
- auto:translateX="65.0"
- auto:translateY="80.0" >
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0" >
<group
- auto:name="rotationGroup3"
- auto:pivotX="-65.0"
- auto:pivotY="-80.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup3"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines2"
- auto:fillColor="#FF00FF00"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:fillColor="#FF00FF00"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="65.0"
- auto:translateY="80.0" >
+ android:name="translateGroup"
+ android:translateX="65.0"
+ android:translateY="80.0" >
<group
- auto:name="rotationGroupBlue"
- auto:pivotX="-65.0"
- auto:pivotY="-80.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroupBlue"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines3"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
index 43fc7ea..097e028 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable13.xml
@@ -14,25 +14,24 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="600" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="600" >
<group>
<path
- auto:name="pie1"
- auto:fillColor="#ffffffff"
- auto:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="1" />
+ android:name="pie1"
+ android:fillColor="#ffffffff"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="1" />
<path
- auto:name="half"
- auto:fillColor="#FFFF0000"
- auto:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="5" />
+ android:name="half"
+ android:fillColor="#FFFF0000"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="5" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
index 5b4fdd1..102ae7a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable14.xml
@@ -14,26 +14,25 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="500"
- auto:viewportWidth="800" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="500"
+ android:viewportWidth="800" >
<group
- auto:pivotX="90"
- auto:pivotY="100"
- auto:rotation="20">
+ android:pivotX="90"
+ android:pivotY="100"
+ android:rotation="20">
<path
- auto:name="pie2"
- auto:pathData="M200,350 l 50,-25
+ android:name="pie2"
+ android:pathData="M200,350 l 50,-25
a25,12 -30 0,1 100,-50 l 50,-25
a25,25 -30 0,1 100,-50 l 50,-25
a25,37 -30 0,1 100,-50 l 50,-25
a25,50 -30 0,1 100,-50 l 50,-25"
- auto:fillColor="#00000000"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10" />
+ android:fillColor="#00000000"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
index f4ef87f..bdfcf81 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable15.xml
@@ -14,22 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="500" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="500" >
<group
- auto:pivotX="250"
- auto:pivotY="200"
- auto:rotation="180">
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="180">
<path
- auto:name="house"
- auto:fillColor="#ff440000"
- auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="10" />
+ android:name="house"
+ android:fillColor="#ff440000"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
index 0c64bca..ed1efa0 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable16.xml
@@ -14,35 +14,34 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200" >
<group>
<path
- auto:name="background1"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background1"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
<path
- auto:name="background2"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background2"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
</group>
<group
- auto:pivotX="100"
- auto:pivotY="100"
- auto:rotation="90"
- auto:scaleX="0.75"
- auto:scaleY="0.5"
- auto:translateX="0.0"
- auto:translateY="100.0">
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90"
+ android:scaleX="0.75"
+ android:scaleY="0.5"
+ android:translateX="0.0"
+ android:translateY="100.0">
<path
- auto:name="twoLines"
- auto:pathData="M 100,10 v 90 M 10,100 h 90"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10" />
+ android:name="twoLines"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
index 28cf09a..ba15f41 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable17.xml
@@ -13,18 +13,17 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:width="64dp"
- auto:height="64dp" auto:viewportWidth="1200"
- auto:viewportHeight="600">
+ android:width="64dp"
+ android:height="64dp" android:viewportWidth="1200"
+ android:viewportHeight="600">
<group>
<path
- auto:name="house"
- auto:pathData="M200,300 Q400,50 600,300 T1000,300"
- auto:fillColor="#00000000"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="10"/>
+ android:name="house"
+ android:pathData="M200,300 Q400,50 600,300 T1000,300"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="10"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
index d66d4ff..ee2122a 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable18.xml
@@ -14,19 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="500" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="500" >
<group>
<path
- auto:name="house"
- auto:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- auto:fillColor="#00000000"
- auto:strokeColor="#FFFFFF00"
- auto:strokeWidth="10" />
+ android:name="house"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFFFF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
index 3a6559d..b98e1de 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable19.xml
@@ -14,21 +14,20 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="800"
- auto:viewportWidth="1000" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="800"
+ android:viewportWidth="1000" >
<group>
<path
- auto:name="house"
- auto:pathData="M10,300 Q400,550 600,300 T1000,300"
- auto:pivotX="90"
- auto:pivotY="100"
- auto:fillColor="#00000000"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="60" />
+ android:name="house"
+ android:pathData="M10,300 Q400,550 600,300 T1000,300"
+ android:pivotX="90"
+ android:pivotY="100"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="60" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
index d6fd704..1c86818 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable20.xml
@@ -14,22 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="480"
- auto:viewportWidth="480" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="480"
+ android:viewportWidth="480" >
<group>
<path
- auto:name="edit"
- auto:fillColor="#FF00FFFF"
- auto:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+ android:name="edit"
+ android:fillColor="#FF00FFFF"
+ android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
- auto:strokeColor="#FF000000"
- auto:strokeWidth="10" />
+ android:strokeColor="#FF000000"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
index 9136b73..247f6bc 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable21.xml
@@ -14,35 +14,34 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200" >
<group>
<path
- auto:name="background1"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background1"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
<path
- auto:name="background2"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
- auto:fillColor="#FF000000"/>
+ android:name="background2"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z"
+ android:fillColor="#FF000000"/>
</group>
<group
- auto:pivotX="0"
- auto:pivotY="0"
- auto:rotation="90"
- auto:scaleX="0.75"
- auto:scaleY="0.5"
- auto:translateX="100.0"
- auto:translateY="100.0">
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="90"
+ android:scaleX="0.75"
+ android:scaleY="0.5"
+ android:translateX="100.0"
+ android:translateY="100.0">
<path
- auto:name="twoLines"
- auto:pathData="M 100,10 v 90 M 10,100 h 90"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="10" />
+ android:name="twoLines"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
index 2b33a89..39d891f 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable22.xml
@@ -14,53 +14,52 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
- <group auto:name="backgroundGroup" >
+ <group android:name="backgroundGroup" >
<path
- auto:name="background1"
- auto:fillColor="#80000000"
- auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background1"
+ android:fillColor="#80000000"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#80000000"
- auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background2"
+ android:fillColor="#80000000"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
</group>
<group
- auto:name="translateToCenterGroup"
- auto:translateX="50.0"
- auto:translateY="90.0" >
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
<path
- auto:name="twoLines"
- auto:pathData="M 0,0 v 100 M 0,0 h 100"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 0,0 v 100 M 0,0 h 100"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines1"
- auto:pathData="M 0,0 v 100 M 0,0 h 100"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="M 0,0 v 100 M 0,0 h 100"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="130.0"
- auto:translateY="160.0" >
- <group auto:name="scaleGroup" >
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0" >
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines2"
- auto:pathData="M 0,0 v 100 M 0,0 h 100"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:pathData="M 0,0 v 100 M 0,0 h 100"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
index d5759f9..4a1c062 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable23.xml
@@ -14,67 +14,66 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
- <group auto:name="backgroundGroup" >
+ <group android:name="backgroundGroup" >
<path
- auto:name="background1"
- auto:fillColor="#80000000"
- auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background1"
+ android:fillColor="#80000000"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#80000000"
- auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background2"
+ android:fillColor="#80000000"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
</group>
<group
- auto:name="translateToCenterGroup"
- auto:translateX="50.0"
- auto:translateY="90.0" >
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
<path
- auto:name="twoLines"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0" >
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
<path
- auto:name="twoLines1"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="130.0"
- auto:translateY="160.0" >
- <group auto:name="scaleGroup" >
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0" >
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines3"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
<group
- auto:name="translateGroupHalf"
- auto:translateX="65.0"
- auto:translateY="80.0" >
- <group auto:name="scaleGroup" >
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0" >
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines2"
- auto:pathData="@string/twoLinePathData"
- auto:fillColor="#FFFFFFFF"
- auto:strokeColor="#FFFFFFFF"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="?android:attr/colorForeground"
+ android:strokeColor="?android:attr/colorForeground"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
index b054692..a7a8bd3 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable24.xml
@@ -14,67 +14,66 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
- <group auto:name="backgroundGroup">
+ <group android:name="backgroundGroup">
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" />
</group>
<group
- auto:name="translateToCenterGroup"
- auto:translateX="50.0"
- auto:translateY="90.0" >
+ android:name="translateToCenterGroup"
+ android:translateX="50.0"
+ android:translateY="90.0" >
<path
- auto:name="twoLines"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FFFF0000"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FFFF0000"
+ android:strokeWidth="20" />
<group
- auto:name="rotationGroup"
- auto:pivotX="0.0"
- auto:pivotY="0.0"
- auto:rotation="-45.0">
+ android:name="rotationGroup"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0">
<path
- auto:name="twoLines1"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF00FF00"
- auto:strokeWidth="20" />
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="20" />
<group
- auto:name="translateGroup"
- auto:translateX="130.0"
- auto:translateY="160.0">
- <group auto:name="scaleGroup" >
+ android:name="translateGroup"
+ android:translateX="130.0"
+ android:translateY="160.0">
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines3"
- auto:pathData="@string/twoLinePathData"
- auto:strokeColor="#FF0000FF"
- auto:strokeWidth="20" />
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="20" />
</group>
</group>
<group
- auto:name="translateGroupHalf"
- auto:translateX="65.0"
- auto:translateY="80.0">
- <group auto:name="scaleGroup" >
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0">
+ <group android:name="scaleGroup" >
<path
- auto:name="twoLines2"
- auto:pathData="@string/twoLinePathData"
- auto:fillColor="#FFFFFFFF"
- auto:strokeColor="#FFFFFFFF"
- auto:strokeWidth="20" />
+ android:name="twoLines2"
+ android:pathData="@string/twoLinePathData"
+ android:fillColor="?android:attr/colorForeground"
+ android:strokeColor="?android:attr/colorForeground"
+ android:strokeWidth="20" />
</group>
</group>
</group>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
index 7a94ed6..7c9e771 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable25.xml
@@ -14,70 +14,69 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:width="64dp"
- auto:viewportHeight="400"
- auto:viewportWidth="400" >
+ android:height="64dp"
+ android:width="64dp"
+ android:viewportHeight="400"
+ android:viewportWidth="400" >
<group
- auto:name="FirstLevelGroup"
- auto:translateX="100.0"
- auto:translateY="0.0" >
+ android:name="FirstLevelGroup"
+ android:translateX="100.0"
+ android:translateY="0.0" >
<group
- auto:name="SecondLevelGroup1"
- auto:translateX="-100.0"
- auto:translateY="50.0" >
+ android:name="SecondLevelGroup1"
+ android:translateX="-100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF00FF00"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF00FF00"
+ android:pathData="@string/rectangle200" />
<group
- auto:name="ThridLevelGroup1"
- auto:translateX="-100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup1"
+ android:translateX="-100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF0000FF"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF0000FF"
+ android:pathData="@string/rectangle200" />
</group>
<group
- auto:name="ThridLevelGroup2"
- auto:translateX="100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup2"
+ android:translateX="100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF000000"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF000000"
+ android:pathData="@string/rectangle200" />
</group>
</group>
<group
- auto:name="SecondLevelGroup2"
- auto:translateX="100.0"
- auto:translateY="50.0" >
+ android:name="SecondLevelGroup2"
+ android:translateX="100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF0000FF"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF0000FF"
+ android:pathData="@string/rectangle200" />
<group
- auto:name="ThridLevelGroup3"
- auto:translateX="-100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup3"
+ android:translateX="-100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FFFF0000"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FFFF0000"
+ android:pathData="@string/rectangle200" />
</group>
<group
- auto:name="ThridLevelGroup4"
- auto:translateX="100.0"
- auto:translateY="50.0" >
+ android:name="ThridLevelGroup4"
+ android:translateX="100.0"
+ android:translateY="50.0" >
<path
- auto:fillColor="#FF00FF00"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FF00FF00"
+ android:pathData="@string/rectangle200" />
</group>
</group>
<path
- auto:fillColor="#FFFF0000"
- auto:pathData="@string/rectangle200" />
+ android:fillColor="#FFFF0000"
+ android:pathData="@string/rectangle200" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
index b2dd4a3..eda06d8 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable26.xml
@@ -14,33 +14,32 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200"
- auto:width="64dp" >
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
<group>
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
</group>
<group
- auto:translateX="50"
- auto:translateY="50" >
+ android:translateX="50"
+ android:translateY="50" >
<path
- auto:name="twoLines"
- auto:pathData="M 100,20 l 0 80 l -30 -80"
- auto:strokeColor="#FF00FF00"
- auto:strokeLineCap="butt"
- auto:strokeLineJoin="miter"
- auto:strokeMiterLimit="5"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 100,20 l 0 80 l -30 -80"
+ android:strokeColor="#FF00FF00"
+ android:strokeLineCap="butt"
+ android:strokeLineJoin="miter"
+ android:strokeMiterLimit="5"
+ android:strokeWidth="20" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
index b8f88ce..cd46dd9 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable27.xml
@@ -14,33 +14,32 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200"
- auto:width="64dp" >
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
<group>
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
</group>
<group
- auto:translateX="50"
- auto:translateY="50" >
+ android:translateX="50"
+ android:translateY="50" >
<path
- auto:name="twoLines"
- auto:pathData="M 100,20 l 0 80 l -30 -80"
- auto:strokeColor="#FF00FF00"
- auto:strokeLineCap="round"
- auto:strokeLineJoin="round"
- auto:strokeMiterLimit="10"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 100,20 l 0 80 l -30 -80"
+ android:strokeColor="#FF00FF00"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeMiterLimit="10"
+ android:strokeWidth="20" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
index 30c7fce..812af6b 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable28.xml
@@ -14,34 +14,33 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="64dp"
- auto:viewportHeight="200"
- auto:viewportWidth="200"
- auto:width="64dp"
- auto:autoMirrored="true" >
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp"
+ android:autoMirrored="true" >
<group>
<path
- auto:name="background1"
- auto:fillColor="#FF000000"
- auto:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
<path
- auto:name="background2"
- auto:fillColor="#FF000000"
- auto:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
</group>
<group
- auto:translateX="50"
- auto:translateY="50" >
+ android:translateX="50"
+ android:translateY="50" >
<path
- auto:name="twoLines"
- auto:pathData="M 100,20 l 0 80 l -30 -80"
- auto:strokeColor="#FF00FF00"
- auto:strokeLineCap="square"
- auto:strokeLineJoin="bevel"
- auto:strokeMiterLimit="10"
- auto:strokeWidth="20" />
+ android:name="twoLines"
+ android:pathData="M 100,20 l 0 80 l -30 -80"
+ android:strokeColor="#FF00FF00"
+ android:strokeLineCap="square"
+ android:strokeLineJoin="bevel"
+ android:strokeMiterLimit="10"
+ android:strokeWidth="20" />
</group>
</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
index 2ac1d42..b24d31c 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable29.xml
@@ -14,16 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="48dp"
- auto:width="48dp"
- auto:viewportHeight="1"
- auto:viewportWidth="1" >
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="1"
+ android:viewportWidth="1" >
<group>
<path
- auto:name="box1"
- auto:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
- auto:fillColor="#ff00ff00"/>
+ android:name="box1"
+ android:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z"
+ android:fillColor="#ff00ff00"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
index 6abb455..24f7372 100644
--- a/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable30.xml
@@ -14,16 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:auto="http://schemas.android.com/apk/res-auto"
- auto:height="48dp"
- auto:width="48dp"
- auto:viewportHeight="48"
- auto:viewportWidth="48" >
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
<group>
<path
- auto:name="plus1"
- auto:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
- auto:fillColor="#ff00ff00"/>
+ android:name="plus1"
+ android:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
+ android:fillColor="#ff00ff00"/>
</group>
</vector>
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml
new file mode 100644
index 0000000..828f0d9
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale0.xml
@@ -0,0 +1,57 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="@color/color0"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="@color/color2"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="-90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="@string/triangle100"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml
new file mode 100644
index 0000000..530c73b
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale1.xml
@@ -0,0 +1,52 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:scaleX="-1"
+ android:scaleY="-1" >
+ <group
+ android:scaleX="-1"
+ android:scaleY="-1" >
+ <group
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="45" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml
new file mode 100644
index 0000000..200eb61
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale2.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:scaleX="2"
+ android:scaleY="0.5" >
+ <group
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="45" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml
new file mode 100644
index 0000000..a40fc9c2
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_drawable_scale3.xml
@@ -0,0 +1,62 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="64dp"
+ android:viewportHeight="200"
+ android:viewportWidth="200"
+ android:width="64dp" >
+
+ <group>
+ <path
+ android:name="background1"
+ android:fillColor="#FF000000"
+ android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+ <path
+ android:name="background2"
+ android:fillColor="#FF000000"
+ android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+ </group>
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="45" >
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <group
+ android:pivotX="0"
+ android:pivotY="0"
+ android:rotation="-90" >
+ <group
+ android:scaleX="1.5"
+ android:scaleY="1" >
+ <path
+ android:name="twoLines"
+ android:fillColor="#FFFF0000"
+ android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+ android:strokeColor="#FF00FF00"
+ android:strokeWidth="10" />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_test01.xml b/graphics/drawable/teststatic/res/drawable/vector_test01.xml
new file mode 100644
index 0000000..8b891d6
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_test01.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at"+
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="128dp"
+ android:width="128dp"
+ android:viewportHeight="512"
+ android:viewportWidth="512" >
+
+ <group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="4"
+ android:fillColor="#00000000" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/graphics/drawable/teststatic/res/drawable/vector_test02.xml b/graphics/drawable/teststatic/res/drawable/vector_test02.xml
new file mode 100644
index 0000000..e0af323
--- /dev/null
+++ b/graphics/drawable/teststatic/res/drawable/vector_test02.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at"+
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="128dp"
+ android:width="128dp"
+ android:viewportHeight="512"
+ android:viewportWidth="512" >
+
+ <group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+ android:strokeColor="#FF0000FF"
+ android:strokeWidth="4"
+ android:fillColor="#00000000" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml b/graphics/drawable/teststatic/res/values/colors.xml
similarity index 60%
rename from v17/leanback/res/animator/lb_guidedactions_item_checked.xml
rename to graphics/drawable/teststatic/res/values/colors.xml
index 463b9f7..6eb3036 100644
--- a/v17/leanback/res/animator/lb_guidedactions_item_checked.xml
+++ b/graphics/drawable/teststatic/res/values/colors.xml
@@ -1,6 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,9 +12,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="@integer/lb_guidedactions_item_animation_duration"
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType" />
+<resources>
+ <color name="color0">#a6e4ea</color>
+ <color name="color1">#ff3838</color>
+ <color name="color2">#ffff51</color>
+ <color name="color3">#0ed300</color>
+</resources>
diff --git a/graphics/drawable/teststatic/res/values/strings.xml b/graphics/drawable/teststatic/res/values/strings.xml
index c5451c88..065e7d9 100644
--- a/graphics/drawable/teststatic/res/values/strings.xml
+++ b/graphics/drawable/teststatic/res/values/strings.xml
@@ -25,4 +25,5 @@
<string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string>
<string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string>
<string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
-</resources>
\ No newline at end of file
+ <string name="triangle100">"M 100, 0 l 0, 100, -100, 0 z"</string>
+</resources>
diff --git a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
index 8bb766e5..c92ff47 100644
--- a/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
+++ b/graphics/drawable/teststatic/src/android/support/test/vectordrawable/TestActivity.java
@@ -34,6 +34,10 @@
private static final String LOGCAT = "VectorDrawable1";
protected int[] icon = {
+ R.drawable.vector_drawable_scale0,
+ R.drawable.vector_drawable_scale1,
+ R.drawable.vector_drawable_scale2,
+ R.drawable.vector_drawable_scale3,
R.drawable.vector_drawable01,
R.drawable.vector_drawable02,
R.drawable.vector_drawable03,
@@ -64,6 +68,8 @@
R.drawable.vector_drawable28,
R.drawable.vector_drawable29,
R.drawable.vector_drawable30,
+ R.drawable.vector_test01,
+ R.drawable.vector_test02
};
private static final int EXTRA_TESTS = 2;
@@ -85,8 +91,10 @@
time = android.os.SystemClock.currentThreadTimeMillis()-time;
// Testing Tint on one particular case.
- d[3].setTint(0x8000FF00);
- d[3].setTintMode(Mode.MULTIPLY);
+ if (d.length > 3) {
+ d[3].setTint(0x8000FF00);
+ d[3].setTintMode(Mode.MULTIPLY);
+ }
// Testing Constant State like operation by creating the first 2 icons
// from the 3rd one's constant state.
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java b/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
new file mode 100644
index 0000000..e6b2e14
--- /dev/null
+++ b/graphics/drawable/util/src/android/support/graphics/drawable/AndroidResources.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.support.graphics.drawable;
+
+public class AndroidResources {
+
+ // Resources ID generated in the latest R.java for framework.
+ static final int[] styleable_VectorDrawableTypeArray = {
+ android.R.attr.name, android.R.attr.tint, android.R.attr.height,
+ android.R.attr.width, android.R.attr.alpha, android.R.attr.autoMirrored,
+ android.R.attr.mode, android.R.attr.viewportWidth, android.R.attr.viewportHeight
+ };
+ static final int styleable_VectorDrawable_alpha = 4;
+ static final int styleable_VectorDrawable_autoMirrored = 5;
+ static final int styleable_VectorDrawable_height = 2;
+ static final int styleable_VectorDrawable_name = 0;
+ static final int styleable_VectorDrawable_tint = 1;
+ static final int styleable_VectorDrawable_Mode = 6;
+ static final int styleable_VectorDrawable_viewportHeight = 8;
+ static final int styleable_VectorDrawable_viewportWidth = 7;
+ static final int styleable_VectorDrawable_width = 3;
+ static final int[] styleable_VectorDrawableGroup = {
+ android.R.attr.name, android.R.attr.pivotX, android.R.attr.pivotY,
+ android.R.attr.scaleX, android.R.attr.scaleY, android.R.attr.rotation,
+ android.R.attr.translateX, android.R.attr.translateY
+ };
+ static final int styleable_VectorDrawableGroup_name = 0;
+ static final int styleable_VectorDrawableGroup_pivotX = 1;
+ static final int styleable_VectorDrawableGroup_pivotY = 2;
+ static final int styleable_VectorDrawableGroup_rotation = 5;
+ static final int styleable_VectorDrawableGroup_scaleX = 3;
+ static final int styleable_VectorDrawableGroup_scaleY = 4;
+ static final int styleable_VectorDrawableGroup_translateX = 6;
+ static final int styleable_VectorDrawableGroup_translateY = 7;
+ static final int[] styleable_VectorDrawablePath = {
+ android.R.attr.name, android.R.attr.fillColor, android.R.attr.pathData,
+ android.R.attr.strokeColor, android.R.attr.strokeWidth, android.R.attr.trimPathStart,
+ android.R.attr.trimPathEnd, android.R.attr.trimPathOffset, android.R.attr.strokeLineCap,
+ android.R.attr.strokeLineJoin, android.R.attr.strokeMiterLimit,
+ android.R.attr.strokeAlpha, android.R.attr.fillAlpha
+ };
+ static final int styleable_VectorDrawablePath_fillAlpha = 12;
+ static final int styleable_VectorDrawablePath_fillColor = 1;
+ static final int styleable_VectorDrawablePath_name = 0;
+ static final int styleable_VectorDrawablePath_pathData = 2;
+ static final int styleable_VectorDrawablePath_strokeAlpha = 11;
+ static final int styleable_VectorDrawablePath_strokeColor = 3;
+ static final int styleable_VectorDrawablePath_strokeLineCap = 8;
+ static final int styleable_VectorDrawablePath_strokeLineJoin = 9;
+ static final int styleable_VectorDrawablePath_strokeMiterLimit = 10;
+ static final int styleable_VectorDrawablePath_strokeWidth = 4;
+ static final int styleable_VectorDrawablePath_trimPathEnd = 6;
+ static final int styleable_VectorDrawablePath_trimPathOffset = 7;
+ static final int styleable_VectorDrawablePath_trimPathStart = 5;
+ static final int[] styleable_VectorDrawableClipPath = {
+ android.R.attr.name, android.R.attr.pathData
+ };
+ static final int styleable_VectorDrawableClipPath_name = 0;
+ static final int styleable_VectorDrawableClipPath_pathData = 1;
+
+ static final int[] styleable_AnimatedVectorDrawable = {
+ android.R.attr.drawable
+ };
+ static final int styleable_AnimatedVectorDrawable_drawable = 0;
+ static final int[] styleable_AnimatedVectorDrawableTarget = {
+ android.R.attr.name, android.R.attr.animation
+ };
+ static final int styleable_AnimatedVectorDrawableTarget_animation = 1;
+ static final int styleable_AnimatedVectorDrawableTarget_name = 0;
+}
diff --git a/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java b/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
new file mode 100644
index 0000000..161eae6
--- /dev/null
+++ b/graphics/drawable/util/src/android/support/graphics/drawable/TypedArrayUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.support.graphics.drawable;
+
+import android.content.res.TypedArray;
+import org.xmlpull.v1.XmlPullParser;
+
+
+public class TypedArrayUtils {
+ private static final String NAMESPACE = "http://schemas.android.com/apk/res/android";
+
+ public static boolean hasAttribute(XmlPullParser parser, String attrName) {
+ return parser.getAttributeValue(NAMESPACE, attrName) != null;
+ }
+
+ public static float getNamedFloat(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, float defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getFloat(resId, defaultValue);
+ }
+ }
+
+ public static boolean getNamedBoolean(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, boolean defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getBoolean(resId, defaultValue);
+ }
+ }
+
+ public static int getNamedInt(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, int defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getInt(resId, defaultValue);
+ }
+ }
+
+ public static int getNamedColor(TypedArray a, XmlPullParser parser, String attrName,
+ int resId, int defaultValue) {
+ final boolean hasAttr = hasAttribute(parser, attrName);
+ if (!hasAttr) {
+ return defaultValue;
+ } else {
+ return a.getColor(resId, defaultValue);
+ }
+ }
+}
diff --git a/v17/leanback/.classpath b/v17/leanback/.classpath
index 7bc01d9..f568681 100644
--- a/v17/leanback/.classpath
+++ b/v17/leanback/.classpath
@@ -1,9 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="api21"/>
+ <classpathentry kind="src" path="api23"/>
+ <classpathentry kind="src" path="jbmr2"/>
+ <classpathentry kind="src" path="common"/>
+ <classpathentry kind="src" path="kitkat"/>
+ <classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
diff --git a/v17/leanback/api/current.txt b/v17/leanback/api/current.txt
index 550e838..a4decd8 100644
--- a/v17/leanback/api/current.txt
+++ b/v17/leanback/api/current.txt
@@ -216,7 +216,6 @@
method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
method public android.view.View getButtonActionItemView(int);
method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
- method protected int getContainerIdForBackground();
method public static android.support.v17.leanback.app.GuidedStepFragment getCurrentGuidedStepFragment(android.app.FragmentManager);
method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
@@ -232,6 +231,7 @@
method protected void onAddSharedElementTransition(android.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepFragment);
method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+ method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
@@ -240,7 +240,6 @@
method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
- method protected android.app.Fragment onProvideBackgroundFragment();
method protected void onProvideFragmentTransitions();
method public int onProvideTheme();
method public void popBackStackToGuidedStepFragment(java.lang.Class, int);
@@ -251,13 +250,8 @@
method public void setUiStyle(int);
field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
- field public static final int UI_STYLE_DEFAULT = 0; // 0x0
field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
- }
-
- public static class GuidedStepFragment.GuidedStepBackgroundFragment extends android.app.Fragment {
- ctor public GuidedStepFragment.GuidedStepBackgroundFragment();
- method protected void onProvideFragmentTransitions();
+ field public static final int UI_STYLE_REPLACE = 0; // 0x0
}
public class GuidedStepSupportFragment extends android.support.v4.app.Fragment {
@@ -276,7 +270,6 @@
method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getActions();
method public android.view.View getButtonActionItemView(int);
method public java.util.List<android.support.v17.leanback.widget.GuidedAction> getButtonActions();
- method protected int getContainerIdForBackground();
method public static android.support.v17.leanback.app.GuidedStepSupportFragment getCurrentGuidedStepSupportFragment(android.support.v4.app.FragmentManager);
method public android.support.v17.leanback.widget.GuidanceStylist getGuidanceStylist();
method public android.support.v17.leanback.widget.GuidedActionsStylist getGuidedActionsStylist();
@@ -292,6 +285,7 @@
method protected void onAddSharedElementTransition(android.support.v4.app.FragmentTransaction, android.support.v17.leanback.app.GuidedStepSupportFragment);
method public void onCreateActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
+ method public android.view.View onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
method public void onCreateButtonActions(java.util.List<android.support.v17.leanback.widget.GuidedAction>, android.os.Bundle);
method public android.support.v17.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
method public android.support.v17.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
@@ -300,7 +294,6 @@
method public void onGuidedActionEdited(android.support.v17.leanback.widget.GuidedAction);
method public long onGuidedActionEditedAndProceed(android.support.v17.leanback.widget.GuidedAction);
method public void onGuidedActionFocused(android.support.v17.leanback.widget.GuidedAction);
- method protected android.support.v4.app.Fragment onProvideBackgroundSupportFragment();
method protected void onProvideFragmentTransitions();
method public int onProvideTheme();
method public void popBackStackToGuidedStepSupportFragment(java.lang.Class, int);
@@ -311,13 +304,8 @@
method public void setUiStyle(int);
field public static final java.lang.String EXTRA_UI_STYLE = "uiStyle";
field public static final int UI_STYLE_ACTIVITY_ROOT = 2; // 0x2
- field public static final int UI_STYLE_DEFAULT = 0; // 0x0
field public static final int UI_STYLE_ENTRANCE = 1; // 0x1
- }
-
- public static class GuidedStepSupportFragment.GuidedStepBackgroundSupportFragment extends android.support.v4.app.Fragment {
- ctor public GuidedStepSupportFragment.GuidedStepBackgroundSupportFragment();
- method protected void onProvideFragmentTransitions();
+ field public static final int UI_STYLE_REPLACE = 0; // 0x0
}
public class HeadersFragment extends android.support.v17.leanback.app.BaseRowFragment {
@@ -1040,6 +1028,7 @@
field public static final long ACTION_ID_NO = -9L; // 0xfffffffffffffff7L
field public static final long ACTION_ID_OK = -4L; // 0xfffffffffffffffcL
field public static final long ACTION_ID_YES = -8L; // 0xfffffffffffffff8L
+ field public static final int CHECKBOX_CHECK_SET_ID = -1; // 0xffffffff
field public static final int DEFAULT_CHECK_SET_ID = 1; // 0x1
field public static final int NO_CHECK_SET = 0; // 0x0
}
@@ -1093,6 +1082,8 @@
method public void onAnimateItemFocused(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
method public void onAnimateItemPressed(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
method public void onAnimateItemPressedCancelled(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+ method public void onBindCheckMarkView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
+ method public void onBindChevronView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
method public void onBindViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup);
method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
@@ -1106,6 +1097,7 @@
method public int onProvideLayoutId();
method public void setAsButtonActions();
method public void setEditingMode(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+ method protected void setupImeOptions(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
}
diff --git a/v17/leanback/project.properties b/v17/leanback/project.properties
index 91d2b02..b2ef7dc 100644
--- a/v17/leanback/project.properties
+++ b/v17/leanback/project.properties
@@ -11,5 +11,5 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
-target=android-19
+target=android-23
android.library=true
diff --git a/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml b/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml
deleted file mode 100644
index 86525c8..0000000
--- a/v17/leanback/res/animator/lb_guidedactions_item_unchecked.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="@integer/lb_guidedactions_item_animation_duration"
- android:propertyName="alpha"
- android:valueFrom="1.0"
- android:valueTo="0.0"
- android:valueType="floatType" />
diff --git a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml b/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
deleted file mode 100644
index ec7903b..0000000
--- a/v17/leanback/res/drawable/lb_guidedactions_item_checkmark.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval" >
-
- <size
- android:height="@dimen/lb_guidedactions_item_checkmark_diameter"
- android:width="@dimen/lb_guidedactions_item_checkmark_diameter" />
-
- <solid android:color="@color/lb_tv_white" />
-
-</shape>
diff --git a/v17/leanback/res/layout/lb_guidedactions_item.xml b/v17/leanback/res/layout/lb_guidedactions_item.xml
index 8f5fcb7..831c355 100644
--- a/v17/leanback/res/layout/lb_guidedactions_item.xml
+++ b/v17/leanback/res/layout/lb_guidedactions_item.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
style="?attr/guidedActionItemContainerStyle" >
- <ImageView
+ <android.support.v17.leanback.widget.CheckableImageView
android:id="@+id/guidedactions_item_checkmark"
style="?attr/guidedActionItemCheckmarkStyle"
tools:ignore="ContentDescription" />
diff --git a/v17/leanback/res/layout/lb_guidedstep_background.xml b/v17/leanback/res/layout/lb_guidedstep_background.xml
index 66b68c4..08ea47d 100644
--- a/v17/leanback/res/layout/lb_guidedstep_background.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_background.xml
@@ -17,6 +17,7 @@
<android.support.v17.leanback.widget.NonOverlappingView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/guidedstep_background"
+ android:transitionName="guidedstep_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/guidedStepBackground" />
diff --git a/v17/leanback/res/layout/lb_guidedstep_fragment.xml b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
index 31e2fee..ca6efc4 100644
--- a/v17/leanback/res/layout/lb_guidedstep_fragment.xml
+++ b/v17/leanback/res/layout/lb_guidedstep_fragment.xml
@@ -15,51 +15,57 @@
limitations under the License.
-->
<!-- Layout for the frame of a 2 pane actions fragment. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content_frame"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/guidedstep_root"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
-
- <android.support.v17.leanback.widget.NonOverlappingFrameLayout
- android:id="@+id/content_fragment"
- android:layout_toStartOf="@+id/action_fragment"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true" />
-
- <android.support.v17.leanback.widget.NonOverlappingFrameLayout
- android:id="@+id/action_fragment_root"
- android:transitionName="action_fragment_root"
- android:transitionGroup="false"
+ <LinearLayout
+ android:id="@+id/content_frame"
android:orientation="horizontal"
- android:clipToPadding="false"
- android:clipChildren="false"
- 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_width="match_parent"
+ android:layout_height="match_parent" >
- <android.support.v17.leanback.widget.NonOverlappingView
- android:id="@+id/action_fragment_background"
- android:transitionName="action_fragment_background"
- android:orientation="horizontal"
- android:outlineProvider="paddedBounds"
- android:layout_width="match_parent"
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/content_fragment"
+ android:layout_toStartOf="@+id/action_fragment"
+ android:layout_width="0dp"
+ android:layout_weight="1"
android:layout_height="match_parent"
- android:background="?attr/guidedActionsBackground"
- android:elevation="?attr/guidedActionsElevation" />
+ android:layout_alignParentStart="true" />
- <android.support.v17.leanback.widget.NonOverlappingLinearLayout
- android:id="@+id/action_fragment"
- android:transitionName="action_fragment"
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/action_fragment_root"
+ android:transitionName="action_fragment_root"
android:transitionGroup="false"
android:orientation="horizontal"
- android:layout_width="match_parent"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ android:paddingStart="@dimen/lb_guidedactions_section_shadow_width"
+ android:layout_width="0dp"
+ android:layout_weight="?attr/guidedActionContentWidthWeight"
android:layout_height="match_parent"
- android:elevation="@dimen/lb_guidedactions_elevation" />
- </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
+ android:layout_alignParentEnd="true">
-</LinearLayout>
\ No newline at end of file
+ <android.support.v17.leanback.widget.NonOverlappingView
+ android:id="@+id/action_fragment_background"
+ android:transitionName="action_fragment_background"
+ android:orientation="horizontal"
+ android:outlineProvider="paddedBounds"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/guidedActionsBackground"
+ android:elevation="?attr/guidedActionsElevation" />
+
+ <android.support.v17.leanback.widget.NonOverlappingLinearLayout
+ android:id="@+id/action_fragment"
+ android:transitionName="action_fragment"
+ android:transitionGroup="false"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:elevation="@dimen/lb_guidedactions_elevation" />
+ </android.support.v17.leanback.widget.NonOverlappingFrameLayout>
+
+ </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml b/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
index 7c4dfc3..ef14957 100644
--- a/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
+++ b/v17/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
@@ -16,6 +16,13 @@
-->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" >
+ <fade
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="350">
+ <targets>
+ <target android:targetId="@id/guidedstep_background" />
+ </targets>
+ </fade>
<slide
android:interpolator="@android:interpolator/fast_out_linear_in"
android:duration="350"
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index 9ce1094..cae72e5 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -398,14 +398,6 @@
<attr name="guidedActionItemChevronStyle" format="reference" />
<!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
- is checked. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedactions_item_checked}. -->
- <attr name="guidedActionCheckedAnimation" format="reference" />
- <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
- is unchecked. Default is {@link
- android.support.v17.leanback.R.animator#lb_guidedactions_item_unchecked}. -->
- <attr name="guidedActionUncheckedAnimation" format="reference" />
- <!-- Theme attribute for the animation used in a GuidedActionsPresenter when an action
is pressed. Default is {@link
android.support.v17.leanback.R.animator#lb_guidedactions_item_pressed}. -->
<attr name="guidedActionPressedAnimation" format="reference" />
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index f5f42f2..053c7e0 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -248,10 +248,10 @@
<dimen name="lb_guidedactions_item_text_width">248dp</dimen>
<dimen name="lb_guidedactions_item_text_width_no_icon">284dp</dimen>
<dimen name="lb_guidedactions_item_min_height">64dp</dimen>
- <dimen name="lb_guidedactions_item_start_padding">20dp</dimen>
+ <dimen name="lb_guidedactions_item_start_padding">28dp</dimen>
<dimen name="lb_guidedactions_item_end_padding">28dp</dimen>
<dimen name="lb_guidedactions_item_delimiter_padding">4dp</dimen>
- <dimen name="lb_guidedactions_item_checkmark_diameter">8dp</dimen>
+ <dimen name="lb_guidedactions_item_checkmark_diameter">16dp</dimen>
<dimen name="lb_guidedactions_item_icon_width">32dp</dimen>
<dimen name="lb_guidedactions_item_icon_height">32dp</dimen>
<dimen name="lb_guidedactions_item_title_font_size">18sp</dimen>
diff --git a/v17/leanback/res/values/styles.xml b/v17/leanback/res/values/styles.xml
index 0e5b0b6..094732d 100644
--- a/v17/leanback/res/values/styles.xml
+++ b/v17/leanback/res/values/styles.xml
@@ -456,9 +456,8 @@
<item name="android:layout_height">@dimen/lb_guidedactions_item_checkmark_diameter</item>
<item name="android:layout_gravity">center</item>
<item name="android:layout_marginEnd">@dimen/lb_guidedactions_item_delimiter_padding</item>
- <item name="android:scaleType">center</item>
- <item name="android:src">@drawable/lb_guidedactions_item_checkmark</item>
- <item name="android:visibility">invisible</item>
+ <item name="android:scaleType">centerInside</item>
+ <item name="android:visibility">gone</item>
</style>
<!-- Style for an action's icon in a GuidedActionsStylist's default item layout. -->
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index d00bc36..056ed1f 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- LeanbackBase may be overridden for specific api levels -->
<style name="Theme.LeanbackBase" parent="android:Theme.Holo.NoActionBar">
@@ -118,7 +118,8 @@
<item name="android:windowEnterTransition">@transition/lb_guidedstep_activity_enter</item>
- <item name="guidedStepBackground">?android:attr/windowBackground</item>
+ <item name="guidedStepBackground">?android:attr/colorBackground</item>
+ <item name="android:windowBackground">@null</item>
<item name="guidedStepImeAppearingAnimation">@animator/lb_guidedstep_slide_up</item>
<item name="guidedStepImeDisappearingAnimation">@animator/lb_guidedstep_slide_down</item>
@@ -145,8 +146,6 @@
<item name="guidedActionItemDescriptionStyle">@style/Widget.Leanback.GuidedActionItemDescriptionStyle</item>
<item name="guidedActionItemChevronStyle">@style/Widget.Leanback.GuidedActionItemChevronStyle</item>
- <item name="guidedActionCheckedAnimation">@animator/lb_guidedactions_item_checked</item>
- <item name="guidedActionUncheckedAnimation">@animator/lb_guidedactions_item_unchecked</item>
<item name="guidedActionPressedAnimation">@animator/lb_guidedactions_item_pressed</item>
<item name="guidedActionUnpressedAnimation">@animator/lb_guidedactions_item_unpressed</item>
<item name="guidedActionEnabledChevronAlpha">@string/lb_guidedactions_item_enabled_chevron_alpha</item>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
index 639ee7f..142e971 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapter.java
@@ -98,9 +98,9 @@
/**
* View holder containing a {@link GuidedAction}.
*/
- private static class ActionViewHolder extends ViewHolder {
+ static class ActionViewHolder extends ViewHolder {
- private final GuidedActionsStylist.ViewHolder mStylistViewHolder;
+ final GuidedActionsStylist.ViewHolder mStylistViewHolder;
private GuidedAction mAction;
/**
@@ -128,45 +128,48 @@
}
}
- private RecyclerView mRecyclerView;
private final ActionOnKeyListener mActionOnKeyListener;
private final ActionOnFocusListener mActionOnFocusListener;
private final ActionEditListener mActionEditListener;
private final List<GuidedAction> mActions;
private ClickListener mClickListener;
- private GuidedActionsStylist mStylist;
+ private final GuidedActionsStylist mStylist;
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (v != null && v.getWindowToken() != null && mClickListener != null) {
- ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+ if (v != null && v.getWindowToken() != null && getRecyclerView() != null) {
+ ActionViewHolder avh = (ActionViewHolder)getRecyclerView().getChildViewHolder(v);
GuidedAction action = avh.getAction();
- if (action.isEnabled() && !action.infoOnly()) {
- mClickListener.onGuidedActionClicked(action);
+ if (action.isEditable() || action.isDescriptionEditable()) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme by click");
+ mGroup.openIme(GuidedActionAdapter.this, avh);
+ } else {
+ handleCheckedActions(avh);
+ if (action.isEnabled() && !action.infoOnly()) {
+ performOnActionClick(avh);
+ }
}
}
}
};
- private boolean mImeOpened;
+ GuidedActionAdapterGroup mGroup;
/**
* Constructs a GuidedActionAdapter with the given list of guided actions, the given click and
* focus listeners, and the given presenter.
* @param actions The list of guided actions this adapter will manage.
- * @param clickListener The click listener for items in this adapter.
* @param focusListener The focus listener for items in this adapter.
* @param presenter The presenter that will manage the display of items in this adapter.
*/
public GuidedActionAdapter(List<GuidedAction> actions, ClickListener clickListener,
- FocusListener focusListener, EditListener editListener,
- GuidedActionsStylist presenter) {
+ FocusListener focusListener, GuidedActionsStylist presenter) {
super();
mActions = new ArrayList<GuidedAction>(actions);
mClickListener = clickListener;
mStylist = presenter;
mActionOnKeyListener = new ActionOnKeyListener();
mActionOnFocusListener = new ActionOnFocusListener(focusListener);
- mActionEditListener = new ActionEditListener(editListener);
+ mActionEditListener = new ActionEditListener();
}
/**
@@ -198,6 +201,22 @@
}
/**
+ * Return index of action in array
+ * @param action Action to search index.
+ * @return Index of Action in array.
+ */
+ public int indexOf(GuidedAction action) {
+ return mActions.indexOf(action);
+ }
+
+ /**
+ * @return GuidedActionsStylist used to build the actions list UI.
+ */
+ public GuidedActionsStylist getGuidedActionsStylist() {
+ return mStylist;
+ }
+
+ /**
* Sets the click listener for items managed by this adapter.
* @param clickListener The click listener for this adapter.
*/
@@ -225,24 +244,12 @@
* {@inheritDoc}
*/
@Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mRecyclerView = recyclerView;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public int getItemViewType(int position) {
return mStylist.getItemViewType(mActions.get(position));
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
- mRecyclerView = null;
+ private RecyclerView getRecyclerView() {
+ return mStylist.getActionsGridView();
}
/**
@@ -285,15 +292,6 @@
GuidedAction action = mActions.get(position);
avh.setAction(action);
mStylist.onBindViewHolder(avh.mStylistViewHolder, action);
-
- setupNextImeOptions(avh.mStylistViewHolder.getEditableTitleView());
- setupNextImeOptions(avh.mStylistViewHolder.getEditableDescriptionView());
- }
-
- private void setupNextImeOptions(EditText edit) {
- if (edit != null) {
- edit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
- }
}
/**
@@ -304,31 +302,6 @@
return mActions.size();
}
- private int getNextActionIndex(GuidedAction action, long nextActionId) {
- if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
- int i, size = mActions.size();
- for (i = 0; i < size; i++) {
- GuidedAction a = mActions.get(i);
- if (mActions.get(i) == action) {
- break;
- }
- }
- do {
- i++;
- } while (i < size && !mActions.get(i).isFocusable());
- return (i == size) ? -1 : i;
- } else {
- int i, size = mActions.size();
- for (i = 0; i < size; i++) {
- GuidedAction a = mActions.get(i);
- if (mActions.get(i).getId() == nextActionId) {
- break;
- }
- }
- return (i == size) ? -1 : i;
- }
- }
-
private class ActionOnFocusListener implements View.OnFocusChangeListener {
private FocusListener mFocusListener;
@@ -343,8 +316,8 @@
}
public void unFocus() {
- if (mSelectedView != null) {
- ViewHolder vh = mRecyclerView.getChildViewHolder(mSelectedView);
+ if (mSelectedView != null && getRecyclerView() != null) {
+ ViewHolder vh = getRecyclerView().getChildViewHolder(mSelectedView);
if (vh != null) {
ActionViewHolder avh = (ActionViewHolder)vh;
mStylist.onAnimateItemFocused(avh.mStylistViewHolder, false);
@@ -357,7 +330,10 @@
@Override
public void onFocusChange(View v, boolean hasFocus) {
- ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+ if (getRecyclerView() == null) {
+ return;
+ }
+ ActionViewHolder avh = (ActionViewHolder) getRecyclerView().getChildViewHolder(v);
if (hasFocus) {
mSelectedView = v;
if (mFocusListener != null) {
@@ -375,10 +351,61 @@
}
}
- public void openIme(ActionViewHolder avh) {
- mStylist.setEditingMode(avh.mStylistViewHolder,
- avh.getAction(), true);
- mActionEditListener.openIme(avh);
+ public ActionViewHolder findSubChildViewHolder(View v) {
+ // Needed because RecyclerView.getChildViewHolder does not traverse the hierarchy
+ if (getRecyclerView() == null) {
+ return null;
+ }
+ ActionViewHolder result = null;
+ ViewParent parent = v.getParent();
+ while (parent != getRecyclerView() && parent != null && v != null) {
+ v = (View)parent;
+ parent = parent.getParent();
+ }
+ if (parent != null && v != null) {
+ result = (ActionViewHolder)getRecyclerView().getChildViewHolder(v);
+ }
+ return result;
+ }
+
+ public void handleCheckedActions(ActionViewHolder avh) {
+ GuidedAction action = avh.getAction();
+ int actionCheckSetId = action.getCheckSetId();
+ if (getRecyclerView() != null && actionCheckSetId != GuidedAction.NO_CHECK_SET) {
+ // Find any actions that are checked and are in the same group
+ // as the selected action. Fade their checkmarks out.
+ if (actionCheckSetId != GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ for (int i = 0, size = mActions.size(); i < size; i++) {
+ GuidedAction a = mActions.get(i);
+ if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) {
+ a.setChecked(false);
+ ViewHolder vh = getRecyclerView().findViewHolderForPosition(i);
+ if (vh != null) {
+ GuidedActionsStylist.ViewHolder subViewHolder =
+ ((ActionViewHolder)vh).mStylistViewHolder;
+ mStylist.onAnimateItemChecked(subViewHolder, false);
+ }
+ }
+ }
+ }
+
+ // If we we'ren't already checked, fade our checkmark in.
+ if (!action.isChecked()) {
+ action.setChecked(true);
+ mStylist.onAnimateItemChecked(avh.mStylistViewHolder, true);
+ } else {
+ if (actionCheckSetId == GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ action.setChecked(false);
+ mStylist.onAnimateItemChecked(avh.mStylistViewHolder, false);
+ }
+ }
+ }
+ }
+
+ public void performOnActionClick(ActionViewHolder avh) {
+ if (mClickListener != null) {
+ mClickListener.onGuidedActionClicked(avh.getAction());
+ }
}
private class ActionOnKeyListener implements View.OnKeyListener {
@@ -398,7 +425,7 @@
*/
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (v == null || event == null) {
+ if (v == null || event == null || getRecyclerView() == null) {
return false;
}
boolean handled = false;
@@ -409,7 +436,8 @@
case KeyEvent.KEYCODE_BUTTON_Y:
case KeyEvent.KEYCODE_ENTER:
- ActionViewHolder avh = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
+ ActionViewHolder avh = (ActionViewHolder) getRecyclerView()
+ .getChildViewHolder(v);
GuidedAction action = avh.getAction();
if (!action.isEnabled() || action.infoOnly()) {
@@ -431,7 +459,6 @@
mStylist.onAnimateItemPressed(avh.mStylistViewHolder,
mKeyPressed);
}
- handled = true;
break;
case KeyEvent.ACTION_UP:
if (DEBUG) {
@@ -443,14 +470,6 @@
mKeyPressed = false;
mStylist.onAnimateItemPressed(avh.mStylistViewHolder, mKeyPressed);
}
- if (action.isEditable() || action.isDescriptionEditable()) {
- if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme click");
- openIme(avh);
- } else {
- handleCheckedActions(avh, action);
- mClickListener.onGuidedActionClicked(action);
- }
- handled = true;
break;
default:
break;
@@ -462,175 +481,40 @@
return handled;
}
- private void handleCheckedActions(ActionViewHolder avh, GuidedAction action) {
- int actionCheckSetId = action.getCheckSetId();
- if (actionCheckSetId != GuidedAction.NO_CHECK_SET) {
- // Find any actions that are checked and are in the same group
- // as the selected action. Fade their checkmarks out.
- for (int i = 0, size = mActions.size(); i < size; i++) {
- GuidedAction a = mActions.get(i);
- if (a != action && a.getCheckSetId() == actionCheckSetId && a.isChecked()) {
- a.setChecked(false);
- ViewHolder vh = mRecyclerView.findViewHolderForPosition(i);
- if (vh != null) {
- GuidedActionsStylist.ViewHolder subViewHolder =
- ((ActionViewHolder)vh).mStylistViewHolder;
- mStylist.onAnimateItemChecked(subViewHolder, false);
- }
- }
- }
-
- // If we we'ren't already checked, fade our checkmark in.
- if (!action.isChecked()) {
- action.setChecked(true);
- mStylist.onAnimateItemChecked(avh.mStylistViewHolder, true);
- }
- }
- }
}
private class ActionEditListener implements OnEditorActionListener,
ImeKeyMonitor.ImeKeyListener {
- private EditListener mEditListener;
-
- public ActionEditListener(EditListener listener) {
- mEditListener = listener;
- }
-
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME action: " + actionId);
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_NEXT ||
actionId == EditorInfo.IME_ACTION_DONE) {
- fillAndGoNext(v);
+ mGroup.fillAndGoNext(GuidedActionAdapter.this, v);
handled = true;
} else if (actionId == EditorInfo.IME_ACTION_NONE) {
if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme escape north");
// Escape north handling: stay on current item, but close editor
handled = true;
- fillAndStay(v);
+ mGroup.fillAndStay(GuidedActionAdapter.this, v);
}
return handled;
}
- private void fillAndStay(TextView v) {
- ActionViewHolder avh = findSubChildViewHolder(v);
- updateTextIntoAction(avh, v);
- finishEditing(avh);
- closeIme(v);
- avh.mStylistViewHolder.view.requestFocus();
- }
-
- private void fillAndGoNext(TextView v) {
- boolean handled = false;
- ActionViewHolder avh = findSubChildViewHolder(v);
- updateTextIntoAction(avh, v);
- mClickListener.onGuidedActionClicked(avh.getAction());
- long nextActionId = finishEditing(avh);
- if (nextActionId != GuidedAction.ACTION_ID_CURRENT
- && nextActionId != avh.getAction().getId()) {
- int next = getNextActionIndex(avh.getAction(), nextActionId);
- if (next != -1) {
- ActionViewHolder vh = (ActionViewHolder) mRecyclerView
- .findViewHolderForPosition(next);
- if (vh != null) {
- handled = true;
- if (vh.getAction().isEditable() ||
- vh.getAction().isDescriptionEditable()) {
- if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme of next Action");
- mStylist.setEditingMode(vh.mStylistViewHolder,
- vh.getAction(), true);
- // open Ime on next action.
- openIme(vh);
- } else {
- if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme and focus to next Action");
- // close IME and focus to next (not editable) action
- closeIme(v);
- vh.mStylistViewHolder.view.requestFocus();
- }
- }
- }
- }
- if (!handled) {
- if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme no next action");
- handled = true;
- closeIme(v);
- avh.mStylistViewHolder.view.requestFocus();
- }
- }
-
- private void updateTextIntoAction(ActionViewHolder avh, TextView v) {
- GuidedAction action = avh.getAction();
- if (v == avh.mStylistViewHolder.getDescriptionView()) {
- if (action.getEditDescription() != null) {
- action.setEditDescription(v.getText());
- } else {
- action.setDescription(v.getText());
- }
- } else if (v == avh.mStylistViewHolder.getTitleView()) {
- if (action.getEditTitle() != null) {
- action.setEditTitle(v.getText());
- } else {
- action.setTitle(v.getText());
- }
- }
- }
-
@Override
public boolean onKeyPreIme(EditText editText, int keyCode, KeyEvent event) {
if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME key: " + keyCode);
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
- fillAndStay(editText);
+ mGroup.fillAndStay(GuidedActionAdapter.this, editText);
} else if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() ==
KeyEvent.ACTION_UP) {
- fillAndGoNext(editText);
+ mGroup.fillAndGoNext(GuidedActionAdapter.this, editText);
}
return false;
}
- public void openIme(ActionViewHolder avh) {
- View v = avh.mStylistViewHolder.getEditingView();
- InputMethodManager mgr = (InputMethodManager)
- v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- v.requestFocus();
- mgr.showSoftInput(v, 0);
- if (!mImeOpened) {
- mImeOpened = true;
- mEditListener.onImeOpen();
- }
- }
-
- public long finishEditing(ActionViewHolder avh) {
- long nextActionId = mEditListener.onGuidedActionEdited(avh.getAction());
- mStylist.setEditingMode(avh.mStylistViewHolder, avh.getAction(), false);
- return nextActionId;
- }
-
- public void closeIme(View v) {
- if (mImeOpened) {
- mImeOpened = false;
- InputMethodManager mgr = (InputMethodManager)
- v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- mgr.hideSoftInputFromWindow(v.getWindowToken(), 0);
- mEditListener.onImeClose();
- }
- }
-
- private ActionViewHolder findSubChildViewHolder(View v) {
- // Needed because RecyclerView.getChildViewHolder does not traverse the hierarchy
- ActionViewHolder result = null;
- ViewParent parent = v.getParent();
- while (parent != mRecyclerView && parent != null && v != null) {
- v = (View)parent;
- parent = parent.getParent();
- }
- if (parent != null && v != null) {
- result = (ActionViewHolder)mRecyclerView.getChildViewHolder(v);
- }
- return result;
- }
}
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java
new file mode 100644
index 0000000..8f8951c
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedActionAdapterGroup.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.support.v17.leanback.app.GuidedActionAdapter.ActionViewHolder;
+import android.support.v17.leanback.app.GuidedActionAdapter.ClickListener;
+import android.support.v17.leanback.app.GuidedActionAdapter.EditListener;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.ImeKeyMonitor;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+import java.util.ArrayList;
+
+/**
+ * Internal implementation manages a group of GuidedActionAdapters, control the next action after
+ * editing finished, maintain the Ime open/close status.
+ */
+class GuidedActionAdapterGroup {
+
+ private static final String TAG_EDIT = "EditableAction";
+ private static final boolean DEBUG_EDIT = false;
+
+ ArrayList<GuidedActionAdapter> mAdapters = new ArrayList<GuidedActionAdapter>();
+ private boolean mImeOpened;
+ private EditListener mEditListener;
+
+ GuidedActionAdapterGroup() {
+ }
+
+ public void addAdpter(GuidedActionAdapter adapter) {
+ mAdapters.add(adapter);
+ adapter.mGroup = this;
+ }
+
+ public void setEditListener(EditListener listener) {
+ mEditListener = listener;
+ }
+
+ boolean focusToNextAction(GuidedActionAdapter adapter, GuidedAction action, long nextActionId) {
+ // for ACTION_ID_NEXT, we first find out the matching index in Actions list.
+ int index = 0;
+ if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
+ index = adapter.indexOf(action);
+ if (index < 0) {
+ return false;
+ }
+ // start from next, if reach end, will go next Adapter below
+ index++;
+ }
+
+ int adapterIndex = mAdapters.indexOf(adapter);
+ do {
+ int size = adapter.getCount();
+ if (nextActionId == GuidedAction.ACTION_ID_NEXT) {
+ while (index < size && !adapter.getItem(index).isFocusable()) {
+ index++;
+ }
+ } else {
+ while (index < size && adapter.getItem(index).getId() != nextActionId) {
+ index++;
+ }
+ }
+ if (index < size) {
+ ActionViewHolder vh = (ActionViewHolder) adapter.getGuidedActionsStylist()
+ .getActionsGridView().findViewHolderForPosition(index);
+ if (vh != null) {
+ if (vh.getAction().isEditable() || vh.getAction().isDescriptionEditable()) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "openIme of next Action");
+ // open Ime on next action.
+ openIme(adapter, vh);
+ } else {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme and focus to next Action");
+ // close IME and focus to next (not editable) action
+ closeIme(vh.mStylistViewHolder.view);
+ vh.mStylistViewHolder.view.requestFocus();
+ }
+ return true;
+ }
+ return false;
+ }
+ // search from index 0 of next Adapter
+ adapterIndex++;
+ if (adapterIndex >= mAdapters.size()) {
+ break;
+ }
+ adapter = mAdapters.get(adapterIndex);
+ index = 0;
+ } while (true);
+ return false;
+ }
+
+ public void openIme(GuidedActionAdapter adapter, ActionViewHolder avh) {
+ adapter.getGuidedActionsStylist().setEditingMode(avh.mStylistViewHolder, avh.getAction(),
+ true);
+ View v = avh.mStylistViewHolder.getEditingView();
+ if (v == null) {
+ return;
+ }
+ InputMethodManager mgr = (InputMethodManager)
+ v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ v.requestFocus();
+ mgr.showSoftInput(v, 0);
+ if (!mImeOpened) {
+ mImeOpened = true;
+ mEditListener.onImeOpen();
+ }
+ }
+
+ public void closeIme(View v) {
+ if (mImeOpened) {
+ mImeOpened = false;
+ InputMethodManager mgr = (InputMethodManager)
+ v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ mgr.hideSoftInputFromWindow(v.getWindowToken(), 0);
+ mEditListener.onImeClose();
+ }
+ }
+
+ private long finishEditing(GuidedActionAdapter adapter, ActionViewHolder avh) {
+ long nextActionId = mEditListener.onGuidedActionEdited(avh.getAction());
+ adapter.getGuidedActionsStylist().setEditingMode(avh.mStylistViewHolder, avh.getAction(),
+ false);
+ return nextActionId;
+ }
+
+ public void fillAndStay(GuidedActionAdapter adapter, TextView v) {
+ ActionViewHolder avh = adapter.findSubChildViewHolder(v);
+ updateTextIntoAction(avh, v);
+ finishEditing(adapter, avh);
+ closeIme(v);
+ avh.mStylistViewHolder.view.requestFocus();
+ }
+
+ public void fillAndGoNext(GuidedActionAdapter adapter, TextView v) {
+ boolean handled = false;
+ ActionViewHolder avh = adapter.findSubChildViewHolder(v);
+ updateTextIntoAction(avh, v);
+ adapter.performOnActionClick(avh);
+ long nextActionId = finishEditing(adapter, avh);
+ if (nextActionId != GuidedAction.ACTION_ID_CURRENT
+ && nextActionId != avh.getAction().getId()) {
+ handled = focusToNextAction(adapter, avh.getAction(), nextActionId);
+ }
+ if (!handled) {
+ if (DEBUG_EDIT) Log.v(TAG_EDIT, "closeIme no next action");
+ handled = true;
+ closeIme(v);
+ avh.mStylistViewHolder.view.requestFocus();
+ }
+ }
+
+ private void updateTextIntoAction(ActionViewHolder avh, TextView v) {
+ GuidedAction action = avh.getAction();
+ if (v == avh.mStylistViewHolder.getDescriptionView()) {
+ if (action.getEditDescription() != null) {
+ action.setEditDescription(v.getText());
+ } else {
+ action.setDescription(v.getText());
+ }
+ } else if (v == avh.mStylistViewHolder.getTitleView()) {
+ if (action.getEditTitle() != null) {
+ action.setEditTitle(v.getText());
+ } else {
+ action.setTitle(v.getText());
+ }
+ }
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
index 15f88d6..cb6859d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -74,6 +74,11 @@
* <li>{@link #add(FragmentManager, GuidedStepFragment)} or {@link #add(FragmentManager,
* GuidedStepFragment, int)}, to add GuidedStepFragment on top of existing Fragments or
* replacing existing GuidedStepFragment when moving forward to next step.</li>
+ * <li>{@link #finishGuidedStepFragments()} can either finish the activity or pop all
+ * GuidedStepFragment from stack.
+ * <li>If app chooses not to use the helper function, it is the app's responsibility to call
+ * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
+ * need pops to.
* </ul>
* <h3>Theming and Stylists</h3>
* <p>
@@ -139,15 +144,13 @@
private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepFragment";
private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
- private static final String ENTRY_NAME_DEFAULT = "GuidedStepDefault";
+ private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
- private static final boolean IS_FRAMEWORK_FRAGMENT = true;
-
/**
* Fragment argument name for UI style. The argument value is persisted in fragment state.
- * The value is initially {@link #UI_STYLE_DEFAULT} and might be changed in one of the three
+ * The value is initially {@link #UI_STYLE_ENTRANCE} and might be changed in one of the three
* helper functions:
* <ul>
* <li>{@link #addAsRoot(Activity, GuidedStepFragment, int)}</li>
@@ -157,7 +160,7 @@
* <p>
* Argument value can be either:
* <ul>
- * <li>{@link #UI_STYLE_DEFAULT}</li>
+ * <li>{@link #UI_STYLE_REPLACE}</li>
* <li>{@link #UI_STYLE_ENTRANCE}</li>
* <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
* </ul>
@@ -165,42 +168,37 @@
public static final String EXTRA_UI_STYLE = "uiStyle";
/**
- * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned
- * in GuidedStepFragment constructor. This is the case that we use GuidedStepFragment to
- * replace another existing GuidedStepFragment when moving forward to next step. Default
- * behavior of this style is:
+ * This is the case that we use GuidedStepFragment to replace another existing
+ * GuidedStepFragment when moving forward to next step. Default behavior of this style is:
* <ul>
- * <li> Enter transition slides in from END(right), exit transition slide out to START(left).
+ * <li>Enter transition slides in from END(right), exit transition same as
+ * {@link #UI_STYLE_ENTRANCE}.
* </li>
- * <li> No background, see {@link #onProvideBackgroundFragment()}.</li>
* </ul>
*/
- public static final int UI_STYLE_DEFAULT = 0;
+ public static final int UI_STYLE_REPLACE = 0;
/**
- * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show
- * GuidedStepFragment on top of other content. The default behavior of this style:
+ * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
+ * GuidedStepFragment constructor. This is the case that we show GuidedStepFragment on top of
+ * other content. The default behavior of this style:
* <ul>
- * <li>Enter transition slides in from two sides, exit transition is inherited from
- * {@link #UI_STYLE_DEFAULT}. Note: Changing exit transition by UI style is not working because
- * fragment transition asks for exit transition before UI style is restored in Fragment
+ * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
+ * Background will be faded in. Note: Changing exit transition by UI style is not working
+ * because fragment transition asks for exit transition before UI style is restored in Fragment
* .onCreate().</li>
- * <li> {@link #onProvideBackgroundFragment()} will create {@link GuidedStepBackgroundFragment}
- * to covering underneath content. The activity must provide a container to host background
- * fragment and override {@link #getContainerIdForBackground()}</li>
* </ul>
*/
public static final int UI_STYLE_ENTRANCE = 1;
/**
- * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
- * GuidedStepFragment in a separate activity. The default behavior of this style:
+ * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
+ * GuidedStepFragment in a separate activity. The default behavior of this style:
* <ul>
- * <li> Enter transition is assigned null (will rely on activity transition), exit transition is
- * same as {@link #UI_STYLE_DEFAULT}. Note: Changing exit transition by UI style is not working
+ * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
+ * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
* because fragment transition asks for exit transition before UI style is restored in
* Fragment.onCreate().</li>
- * <li> No background, see {@link #onProvideBackgroundFragment()}.
* </ul>
*/
public static final int UI_STYLE_ACTIVITY_ROOT = 2;
@@ -215,6 +213,7 @@
private GuidedActionsStylist mButtonActionsStylist;
private GuidedActionAdapter mAdapter;
private GuidedActionAdapter mButtonAdapter;
+ private GuidedActionAdapterGroup mAdapterGroup;
private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
private int mSelectedIndex = -1;
@@ -341,7 +340,7 @@
* GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
* transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
* is pressed.
- * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_DEFAULT}
+ * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE}
* <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
* <p>
* Note: currently fragments added using this method must be created programmatically rather
@@ -359,7 +358,7 @@
* GuidedStepFragments in the stack, and configuring the fragment-to-fragment custom
* transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
* is pressed.
- * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_DEFAULT} and
+ * <li>If current fragment on stack is GuidedStepFragment: assign {@link #UI_STYLE_REPLACE} and
* {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepFragment)} will be called
* to perform shared element transition between GuidedStepFragments.
* <li>If current fragment on stack is not GuidedStepFragment: assign {@link #UI_STYLE_ENTRANCE}
@@ -374,32 +373,24 @@
public static int add(FragmentManager fragmentManager, GuidedStepFragment fragment, int id) {
GuidedStepFragment current = getCurrentGuidedStepFragment(fragmentManager);
boolean inGuidedStep = current != null;
- if (IS_FRAMEWORK_FRAGMENT && Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23
- && !inGuidedStep && fragment.getContainerIdForBackground() != View.NO_ID) {
- // workaround b/22631964 for framework fragment
- fragmentManager.beginTransaction()
- .replace(id, new DummyFragment(), TAG_LEAN_BACK_ACTIONS_FRAGMENT)
- .replace(fragment.getContainerIdForBackground(), new DummyFragment())
- .commit();
- }
FragmentTransaction ft = fragmentManager.beginTransaction();
- fragment.setUiStyle(inGuidedStep ? UI_STYLE_DEFAULT : UI_STYLE_ENTRANCE);
+ fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
ft.addToBackStack(fragment.generateStackEntryName());
if (current != null) {
fragment.onAddSharedElementTransition(ft, current);
}
- initialBackground(fragment, id, ft);
return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
}
/**
- * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_DEFAULT} (aka
- * when the GuidedStepFragment replacing an existing GuidedStepFragment).
- * Default implementation establishes connections between background views to morph background
- * bounds change from disappearing GuidedStepFragment into this GuidedStepFragment. The default
+ * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
+ * when the GuidedStepFragment replacing an existing GuidedStepFragment). Default implementation
+ * establishes connections between action background views to morph action background bounds
+ * change from disappearing GuidedStepFragment into this GuidedStepFragment. The default
* implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
* method when modifying the default layout of {@link GuidedActionsStylist}.
+ *
* @see GuidedActionsStylist
* @see #onProvideFragmentTransitions()
* @param ft The FragmentTransaction to add shared element.
@@ -441,7 +432,7 @@
/**
* Generates BackStackEntry name for GuidedStepFragment class or empty String if no entry is
* associated. Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
- * @param uiStyle {@link #UI_STYLE_DEFAULT} or {@link #UI_STYLE_ENTRANCE}
+ * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
* @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
* associated.
*/
@@ -450,8 +441,8 @@
return "";
}
switch (uiStyle) {
- case UI_STYLE_DEFAULT:
- return ENTRY_NAME_DEFAULT + guidedStepFragmentClass.getName();
+ case UI_STYLE_REPLACE:
+ return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
case UI_STYLE_ENTRANCE:
return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
case UI_STYLE_ACTIVITY_ROOT:
@@ -472,14 +463,14 @@
}
/**
- * Returns true if the backstack represents GuidedStepFragment with {@link #UI_STYLE_DEFAULT};
+ * Returns true if the backstack represents GuidedStepFragment with {@link #UI_STYLE_REPLACE};
* false otherwise.
* @param backStackEntryName Name of BackStackEntry.
- * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_DEFAULT};
+ * @return True if the backstack represents GuidedStepFragment with {@link #UI_STYLE_REPLACE};
* false otherwise.
*/
public static boolean isUiStyleDefault(String backStackEntryName) {
- return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_DEFAULT);
+ return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_REPLACE);
}
/**
@@ -488,8 +479,8 @@
* @return Class name of GuidedStepFragment.
*/
public static String getGuidedStepFragmentClassName(String backStackEntryName) {
- if (backStackEntryName.startsWith(ENTRY_NAME_DEFAULT)) {
- return backStackEntryName.substring(ENTRY_NAME_DEFAULT.length());
+ if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
+ return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
} else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
} else {
@@ -516,19 +507,9 @@
FragmentManager fragmentManager = activity.getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
- initialBackground(fragment, id, ft);
return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
}
- static void initialBackground(GuidedStepFragment fragment, int id, FragmentTransaction ft) {
- if (fragment.getContainerIdForBackground() != View.NO_ID) {
- Fragment backgroundFragment = fragment.onProvideBackgroundFragment();
- if (backgroundFragment != null) {
- ft.replace(fragment.getContainerIdForBackground(), backgroundFragment);
- }
- }
- }
-
/**
* Returns the current GuidedStepFragment on the fragment transaction stack.
* @return The current GuidedStepFragment, if any, on the fragment transaction stack.
@@ -542,20 +523,6 @@
}
/**
- * @hide
- */
- public static class DummyFragment extends Fragment {
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View v = new View(inflater.getContext());
- v.setVisibility(View.GONE);
- return v;
- }
- }
-
- /**
* Returns the GuidanceStylist that displays guidance information for the user.
* @return The GuidanceStylist for this fragment.
*/
@@ -753,12 +720,12 @@
* Called by Constructor to provide fragment transitions. The default implementation assigns
* transitions based on {@link #getUiStyle()}:
* <ul>
- * <li> {@link #UI_STYLE_DEFAULT} Slide from/to end(right) for enter transition, slide from/to
+ * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
* start(left) for exit transition, shared element enter transition is set to ChangeBounds.
* <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
- * transition is same as {@link #UI_STYLE_DEFAULT}, no shared element enter transition.
+ * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
* <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
- * activity transition, exit transition is same as {@link #UI_STYLE_DEFAULT}, no shared element
+ * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
* enter transition.
* </ul>
* <p>
@@ -773,7 +740,8 @@
*/
protected void onProvideFragmentTransitions() {
if (Build.VERSION.SDK_INT >= 21) {
- if (getUiStyle() == UI_STYLE_DEFAULT) {
+ final int uiStyle = getUiStyle();
+ if (uiStyle == UI_STYLE_REPLACE) {
Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
TransitionHelper.exclude(enterTransition, R.id.action_fragment_background, true);
TransitionHelper.exclude(enterTransition, R.id.guided_button_actions_background,
@@ -781,7 +749,32 @@
TransitionHelper.exclude(enterTransition, R.id.guided_button_actions_background2,
true);
TransitionHelper.exclude(enterTransition, R.id.guidedactions_selector, true);
+ TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
TransitionHelper.setEnterTransition(this, enterTransition);
+
+ // exit transition is unchanged, same as default UI_STYLE_ENTRANCE
+
+ Object changeBounds = TransitionHelper.createChangeBounds(false);
+ TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
+ } else if (uiStyle == UI_STYLE_ENTRANCE) {
+ Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
+ TransitionHelper.FADE_OUT);
+ TransitionHelper.include(fade, R.id.guidedstep_background);
+ Object slide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
+ Gravity.START);
+ TransitionHelper.include(slide, R.id.content_fragment);
+ TransitionHelper.include(slide, R.id.action_fragment_background);
+ TransitionHelper.include(slide, R.id.guided_button_actions_background);
+ TransitionHelper.include(slide, R.id.guidedactions_selector);
+ TransitionHelper.include(slide, R.id.guidedactions_list);
+ TransitionHelper.include(slide, R.id.guided_button_actions_background2);
+ TransitionHelper.include(slide, R.id.guidedactions_selector2);
+ TransitionHelper.include(slide, R.id.guidedactions_list2);
+ Object enterTransition = TransitionHelper.createTransitionSet(false);
+ TransitionHelper.addTransition(enterTransition, fade);
+ TransitionHelper.addTransition(enterTransition, slide);
+ TransitionHelper.setEnterTransition(this, enterTransition);
+
Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
TransitionHelper.exclude(exitTransition, R.id.action_fragment_background, true);
TransitionHelper.exclude(exitTransition, R.id.guided_button_actions_background,
@@ -790,118 +783,47 @@
TransitionHelper.exclude(exitTransition, R.id.guided_button_actions_background2,
true);
TransitionHelper.exclude(exitTransition, R.id.guidedactions_selector2, true);
+ TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
TransitionHelper.setExitTransition(this, exitTransition);
-
- Object changeBounds = TransitionHelper.createChangeBounds(false);
- TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
- } else if (getUiStyle() == UI_STYLE_ENTRANCE) {
- Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END |
- Gravity.START);
- TransitionHelper.include(enterTransition, R.id.content_fragment);
- TransitionHelper.include(enterTransition, R.id.action_fragment_background);
- TransitionHelper.include(enterTransition, R.id.guided_button_actions_background);
- TransitionHelper.include(enterTransition, R.id.guidedactions_selector);
- TransitionHelper.include(enterTransition, R.id.guidedactions_list);
- TransitionHelper.include(enterTransition, R.id.guided_button_actions_background2);
- TransitionHelper.include(enterTransition, R.id.guidedactions_selector2);
- TransitionHelper.include(enterTransition, R.id.guidedactions_list2);
- TransitionHelper.setEnterTransition(this, enterTransition);
- // exit transition is unchanged, same as UI_STYLE_DEFAULT
// No shared element transition
TransitionHelper.setSharedElementEnterTransition(this, null);
- } else if (getUiStyle() == UI_STYLE_ACTIVITY_ROOT) {
+ } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
// for Activity root, we dont need enter transition, use activity transition
TransitionHelper.setEnterTransition(this, null);
- // exit transition is unchanged, same as UI_STYLE_DEFAULT
+ // exit transition is unchanged, same as UI_STYLE_ENTRANCE
// No shared element transition
TransitionHelper.setSharedElementEnterTransition(this, null);
+ } else {
+ return;
}
}
}
/**
- * Default implementation of background for covering content below GuidedStepFragment.
- * It uses current theme attribute guidedStepBackground which by default is read from
- * android:windowBackground.
+ * Called by onCreateView to inflate background view. Default implementation loads view
+ * from {@link R.layout#lb_guidedstep_background} which holds a reference to
+ * guidedStepBackground.
+ * @param inflater LayoutInflater to load background view.
+ * @param container Parent view of background view.
+ * @param savedInstanceState
+ * @return Created background view or null if no background.
*/
- public static class GuidedStepBackgroundFragment extends Fragment {
- public GuidedStepBackgroundFragment() {
- onProvideFragmentTransitions();
- }
-
- /**
- * Sets fragment transitions for GuidedStepBackgroundFragment. Can be overridden.
- */
- protected void onProvideFragmentTransitions() {
- if (Build.VERSION.SDK_INT >= 21) {
- Object enterTransition = TransitionHelper.createFadeTransition(
- TransitionHelper.FADE_IN|TransitionHelper.FADE_OUT);
- TransitionHelper.setEnterTransition(this, enterTransition);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- Activity activity = getActivity();
- Context themedContext = null;
- if (!isGuidedStepTheme(activity)) {
- // Look up the guidedStepTheme in the activity's currently specified theme. If it
- // exists, replace the theme with its value.
- int resId = R.attr.guidedStepTheme;
- TypedValue typedValue = new TypedValue();
- boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
- if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
- if (found) {
- ContextThemeWrapper themeWrapper =
- new ContextThemeWrapper(activity, typedValue.resourceId);
- if (isGuidedStepTheme(themeWrapper)) {
- themedContext = themeWrapper;
- }
- }
- if (!found) {
- Log.e(TAG, "GuidedStepFragment does not have an appropriate theme set.");
- }
- }
-
- if (themedContext != null) {
- inflater = inflater.cloneInContext(themedContext);
- }
-
- return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
- }
+ public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
}
/**
- * Creates a background fragment for {@link #UI_STYLE_ENTRANCE}, returns null for other cases.
- * Subclass may override the default behavior, e.g. provide different backgrounds
- * for {@link #UI_STYLE_DEFAULT}. Background fragment will be inserted in {@link
- * #getContainerIdForBackground()}.
+ * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
+ * is first initialized. UI style is used to choose different fragment transition animations and
+ * determine if this is the first GuidedStepFragment on backstack. In most cases app does not
+ * directly call this method, app calls helper function
+ * {@link #add(FragmentManager, GuidedStepFragment, int)}. However if the app creates Fragment
+ * transaction and controls backstack by itself, it would need call setUiStyle() to select the
+ * fragment transition to use.
*
- * @return fragment that will be inserted below GuidedStepFragment.
- */
- protected Fragment onProvideBackgroundFragment() {
- if (getUiStyle() == UI_STYLE_ENTRANCE) {
- return new GuidedStepBackgroundFragment();
- }
- return null;
- }
-
- /**
- * Returns container id for inserting {@link #onProvideBackgroundFragment()}. The id should be
- * different than container id for inserting GuidedStepFragment.
- * Default value is {@link View#NO_ID}. Subclass must override to host background fragment.
- * @return container id for inserting {@link #onProvideBackgroundFragment()}
- */
- protected int getContainerIdForBackground() {
- return View.NO_ID;
- }
-
-
- /**
- * Set UI style to fragment arguments, UI style cannot be changed after initialization.
- * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_DEFAULT} or
- * {@link #UI_STYLE_ENTRANCE}.
+ * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+ * {@link #UI_STYLE_ENTRANCE}.
*/
public void setUiStyle(int style) {
int oldStyle = getUiStyle();
@@ -922,15 +844,18 @@
}
/**
- * Read UI style from fragment arguments.
+ * Read UI style from fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when
+ * fragment is first initialized. UI style is used to choose different fragment transition
+ * animations and determine if this is the first GuidedStepFragment on backstack.
*
- * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_DEFAULT} or
+ * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
* {@link #UI_STYLE_ENTRANCE}.
+ * @see #onProvideFragmentTransitions()
*/
public int getUiStyle() {
Bundle b = getArguments();
- if (b == null) return UI_STYLE_DEFAULT;
- return b.getInt(EXTRA_UI_STYLE, UI_STYLE_DEFAULT);
+ if (b == null) return UI_STYLE_ENTRANCE;
+ return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
}
/**
@@ -964,6 +889,9 @@
mGuidanceStylist.onDestroyView();
mActionsStylist.onDestroyView();
mButtonActionsStylist.onDestroyView();
+ mAdapter = null;
+ mButtonAdapter = null;
+ mAdapterGroup = null;
super.onDestroyView();
}
@@ -978,9 +906,10 @@
resolveTheme();
inflater = getThemeInflater(inflater);
- View v = inflater.inflate(R.layout.lb_guidedstep_fragment, container, false);
- ViewGroup guidanceContainer = (ViewGroup) v.findViewById(R.id.content_fragment);
- ViewGroup actionContainer = (ViewGroup) v.findViewById(R.id.action_fragment);
+ ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_guidedstep_fragment,
+ container, false);
+ ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
+ ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
Guidance guidance = onCreateGuidance(savedInstanceState);
View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
@@ -1011,10 +940,12 @@
}
};
- mAdapter = new GuidedActionAdapter(mActions, this, this, editListener,
- mActionsStylist);
- mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, editListener,
- mButtonActionsStylist);
+ mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+ mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, mButtonActionsStylist);
+ mAdapterGroup = new GuidedActionAdapterGroup();
+ mAdapterGroup.addAdpter(mAdapter);
+ mAdapterGroup.addAdpter(mButtonAdapter);
+ mAdapterGroup.setEditListener(editListener);
mActionsStylist.getActionsGridView().setAdapter(mAdapter);
mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
@@ -1032,7 +963,7 @@
TypedValue typedValue = new TypedValue();
if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
typedValue, true)) {
- View actionsRoot = v.findViewById(R.id.action_fragment_root);
+ View actionsRoot = root.findViewById(R.id.action_fragment_root);
float weight = typedValue.getFloat();
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
.getLayoutParams();
@@ -1047,7 +978,11 @@
setSelectedButtonActionPosition(0);
- return v;
+ View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
+ if (backgroundView != null) {
+ root.addView(backgroundView, 0);
+ }
+ return root;
}
@Override
@@ -1079,6 +1014,8 @@
* Convenient method to close GuidedStepFragments on top of other content or finish Activity if
* GuidedStepFragments were started in a separate activity. Pops all stack entries including
* {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
+ * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepFragment,
+ * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
*/
public void finishGuidedStepFragments() {
final FragmentManager fragmentManager = getFragmentManager();
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 864e04f..fae8c50 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -76,6 +76,11 @@
* <li>{@link #add(FragmentManager, GuidedStepSupportFragment)} or {@link #add(FragmentManager,
* GuidedStepSupportFragment, int)}, to add GuidedStepSupportFragment on top of existing Fragments or
* replacing existing GuidedStepSupportFragment when moving forward to next step.</li>
+ * <li>{@link #finishGuidedStepSupportFragments()} can either finish the activity or pop all
+ * GuidedStepSupportFragment from stack.
+ * <li>If app chooses not to use the helper function, it is the app's responsibility to call
+ * {@link #setUiStyle(int)} to select fragment transition and remember the stack entry where it
+ * need pops to.
* </ul>
* <h3>Theming and Stylists</h3>
* <p>
@@ -141,15 +146,13 @@
private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepSupportFragment";
private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
- private static final String ENTRY_NAME_DEFAULT = "GuidedStepDefault";
+ private static final String ENTRY_NAME_REPLACE = "GuidedStepDefault";
private static final String ENTRY_NAME_ENTRANCE = "GuidedStepEntrance";
- private static final boolean IS_FRAMEWORK_FRAGMENT = false;
-
/**
* Fragment argument name for UI style. The argument value is persisted in fragment state.
- * The value is initially {@link #UI_STYLE_DEFAULT} and might be changed in one of the three
+ * The value is initially {@link #UI_STYLE_ENTRANCE} and might be changed in one of the three
* helper functions:
* <ul>
* <li>{@link #addAsRoot(FragmentActivity, GuidedStepSupportFragment, int)}</li>
@@ -159,7 +162,7 @@
* <p>
* Argument value can be either:
* <ul>
- * <li>{@link #UI_STYLE_DEFAULT}</li>
+ * <li>{@link #UI_STYLE_REPLACE}</li>
* <li>{@link #UI_STYLE_ENTRANCE}</li>
* <li>{@link #UI_STYLE_ACTIVITY_ROOT}</li>
* </ul>
@@ -167,42 +170,37 @@
public static final String EXTRA_UI_STYLE = "uiStyle";
/**
- * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned
- * in GuidedStepSupportFragment constructor. This is the case that we use GuidedStepSupportFragment to
- * replace another existing GuidedStepSupportFragment when moving forward to next step. Default
- * behavior of this style is:
+ * This is the case that we use GuidedStepSupportFragment to replace another existing
+ * GuidedStepSupportFragment when moving forward to next step. Default behavior of this style is:
* <ul>
- * <li> Enter transition slides in from END(right), exit transition slide out to START(left).
+ * <li>Enter transition slides in from END(right), exit transition same as
+ * {@link #UI_STYLE_ENTRANCE}.
* </li>
- * <li> No background, see {@link #onProvideBackgroundSupportFragment()}.</li>
* </ul>
*/
- public static final int UI_STYLE_DEFAULT = 0;
+ public static final int UI_STYLE_REPLACE = 0;
/**
- * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show
- * GuidedStepSupportFragment on top of other content. The default behavior of this style:
+ * Default value for argument {@link #EXTRA_UI_STYLE}. The default value is assigned in
+ * GuidedStepSupportFragment constructor. This is the case that we show GuidedStepSupportFragment on top of
+ * other content. The default behavior of this style:
* <ul>
- * <li>Enter transition slides in from two sides, exit transition is inherited from
- * {@link #UI_STYLE_DEFAULT}. Note: Changing exit transition by UI style is not working because
- * fragment transition asks for exit transition before UI style is restored in Fragment
+ * <li>Enter transition slides in from two sides, exit transition slide out to START(left).
+ * Background will be faded in. Note: Changing exit transition by UI style is not working
+ * because fragment transition asks for exit transition before UI style is restored in Fragment
* .onCreate().</li>
- * <li> {@link #onProvideBackgroundSupportFragment()} will create {@link GuidedStepBackgroundSupportFragment}
- * to covering underneath content. The activity must provide a container to host background
- * fragment and override {@link #getContainerIdForBackground()}</li>
* </ul>
*/
public static final int UI_STYLE_ENTRANCE = 1;
/**
- * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
- * GuidedStepSupportFragment in a separate activity. The default behavior of this style:
+ * One possible value of argument {@link #EXTRA_UI_STYLE}. This is the case that we show first
+ * GuidedStepSupportFragment in a separate activity. The default behavior of this style:
* <ul>
- * <li> Enter transition is assigned null (will rely on activity transition), exit transition is
- * same as {@link #UI_STYLE_DEFAULT}. Note: Changing exit transition by UI style is not working
+ * <li>Enter transition is assigned null (will rely on activity transition), exit transition is
+ * same as {@link #UI_STYLE_ENTRANCE}. Note: Changing exit transition by UI style is not working
* because fragment transition asks for exit transition before UI style is restored in
* Fragment.onCreate().</li>
- * <li> No background, see {@link #onProvideBackgroundSupportFragment()}.
* </ul>
*/
public static final int UI_STYLE_ACTIVITY_ROOT = 2;
@@ -217,6 +215,7 @@
private GuidedActionsStylist mButtonActionsStylist;
private GuidedActionAdapter mAdapter;
private GuidedActionAdapter mButtonAdapter;
+ private GuidedActionAdapterGroup mAdapterGroup;
private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
private int mSelectedIndex = -1;
@@ -343,7 +342,7 @@
* GuidedStepSupportFragments in the stack, and configuring the fragment-to-fragment custom
* transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
* is pressed.
- * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_DEFAULT}
+ * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_REPLACE}
* <li>If current fragment on stack is not GuidedStepSupportFragment: assign {@link #UI_STYLE_ENTRANCE}
* <p>
* Note: currently fragments added using this method must be created programmatically rather
@@ -361,7 +360,7 @@
* GuidedStepSupportFragments in the stack, and configuring the fragment-to-fragment custom
* transitions. A backstack entry is added, so the fragment will be dismissed when BACK key
* is pressed.
- * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_DEFAULT} and
+ * <li>If current fragment on stack is GuidedStepSupportFragment: assign {@link #UI_STYLE_REPLACE} and
* {@link #onAddSharedElementTransition(FragmentTransaction, GuidedStepSupportFragment)} will be called
* to perform shared element transition between GuidedStepSupportFragments.
* <li>If current fragment on stack is not GuidedStepSupportFragment: assign {@link #UI_STYLE_ENTRANCE}
@@ -376,32 +375,24 @@
public static int add(FragmentManager fragmentManager, GuidedStepSupportFragment fragment, int id) {
GuidedStepSupportFragment current = getCurrentGuidedStepSupportFragment(fragmentManager);
boolean inGuidedStep = current != null;
- if (IS_FRAMEWORK_FRAGMENT && Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23
- && !inGuidedStep && fragment.getContainerIdForBackground() != View.NO_ID) {
- // workaround b/22631964 for framework fragment
- fragmentManager.beginTransaction()
- .replace(id, new DummyFragment(), TAG_LEAN_BACK_ACTIONS_FRAGMENT)
- .replace(fragment.getContainerIdForBackground(), new DummyFragment())
- .commit();
- }
FragmentTransaction ft = fragmentManager.beginTransaction();
- fragment.setUiStyle(inGuidedStep ? UI_STYLE_DEFAULT : UI_STYLE_ENTRANCE);
+ fragment.setUiStyle(inGuidedStep ? UI_STYLE_REPLACE : UI_STYLE_ENTRANCE);
ft.addToBackStack(fragment.generateStackEntryName());
if (current != null) {
fragment.onAddSharedElementTransition(ft, current);
}
- initialBackground(fragment, id, ft);
return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
}
/**
- * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_DEFAULT} (aka
- * when the GuidedStepSupportFragment replacing an existing GuidedStepSupportFragment).
- * Default implementation establishes connections between background views to morph background
- * bounds change from disappearing GuidedStepSupportFragment into this GuidedStepSupportFragment. The default
+ * Called when this fragment is added to FragmentTransaction with {@link #UI_STYLE_REPLACE} (aka
+ * when the GuidedStepSupportFragment replacing an existing GuidedStepSupportFragment). Default implementation
+ * establishes connections between action background views to morph action background bounds
+ * change from disappearing GuidedStepSupportFragment into this GuidedStepSupportFragment. The default
* implementation heavily relies on {@link GuidedActionsStylist}'s layout, app may override this
* method when modifying the default layout of {@link GuidedActionsStylist}.
+ *
* @see GuidedActionsStylist
* @see #onProvideFragmentTransitions()
* @param ft The FragmentTransaction to add shared element.
@@ -443,7 +434,7 @@
/**
* Generates BackStackEntry name for GuidedStepSupportFragment class or empty String if no entry is
* associated. Note {@link #UI_STYLE_ACTIVITY_ROOT} is not allowed and returns empty String.
- * @param uiStyle {@link #UI_STYLE_DEFAULT} or {@link #UI_STYLE_ENTRANCE}
+ * @param uiStyle {@link #UI_STYLE_REPLACE} or {@link #UI_STYLE_ENTRANCE}
* @return BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
* associated.
*/
@@ -452,8 +443,8 @@
return "";
}
switch (uiStyle) {
- case UI_STYLE_DEFAULT:
- return ENTRY_NAME_DEFAULT + guidedStepFragmentClass.getName();
+ case UI_STYLE_REPLACE:
+ return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
case UI_STYLE_ENTRANCE:
return ENTRY_NAME_ENTRANCE + guidedStepFragmentClass.getName();
case UI_STYLE_ACTIVITY_ROOT:
@@ -474,14 +465,14 @@
}
/**
- * Returns true if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_DEFAULT};
+ * Returns true if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_REPLACE};
* false otherwise.
* @param backStackEntryName Name of BackStackEntry.
- * @return True if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_DEFAULT};
+ * @return True if the backstack represents GuidedStepSupportFragment with {@link #UI_STYLE_REPLACE};
* false otherwise.
*/
public static boolean isUiStyleDefault(String backStackEntryName) {
- return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_DEFAULT);
+ return backStackEntryName != null && backStackEntryName.startsWith(ENTRY_NAME_REPLACE);
}
/**
@@ -490,8 +481,8 @@
* @return Class name of GuidedStepSupportFragment.
*/
public static String getGuidedStepSupportFragmentClassName(String backStackEntryName) {
- if (backStackEntryName.startsWith(ENTRY_NAME_DEFAULT)) {
- return backStackEntryName.substring(ENTRY_NAME_DEFAULT.length());
+ if (backStackEntryName.startsWith(ENTRY_NAME_REPLACE)) {
+ return backStackEntryName.substring(ENTRY_NAME_REPLACE.length());
} else if (backStackEntryName.startsWith(ENTRY_NAME_ENTRANCE)) {
return backStackEntryName.substring(ENTRY_NAME_ENTRANCE.length());
} else {
@@ -518,19 +509,9 @@
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
fragment.setUiStyle(UI_STYLE_ACTIVITY_ROOT);
- initialBackground(fragment, id, ft);
return ft.replace(id, fragment, TAG_LEAN_BACK_ACTIONS_FRAGMENT).commit();
}
- static void initialBackground(GuidedStepSupportFragment fragment, int id, FragmentTransaction ft) {
- if (fragment.getContainerIdForBackground() != View.NO_ID) {
- Fragment backgroundFragment = fragment.onProvideBackgroundSupportFragment();
- if (backgroundFragment != null) {
- ft.replace(fragment.getContainerIdForBackground(), backgroundFragment);
- }
- }
- }
-
/**
* Returns the current GuidedStepSupportFragment on the fragment transaction stack.
* @return The current GuidedStepSupportFragment, if any, on the fragment transaction stack.
@@ -544,20 +525,6 @@
}
/**
- * @hide
- */
- public static class DummyFragment extends Fragment {
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View v = new View(inflater.getContext());
- v.setVisibility(View.GONE);
- return v;
- }
- }
-
- /**
* Returns the GuidanceStylist that displays guidance information for the user.
* @return The GuidanceStylist for this fragment.
*/
@@ -755,12 +722,12 @@
* Called by Constructor to provide fragment transitions. The default implementation assigns
* transitions based on {@link #getUiStyle()}:
* <ul>
- * <li> {@link #UI_STYLE_DEFAULT} Slide from/to end(right) for enter transition, slide from/to
+ * <li> {@link #UI_STYLE_REPLACE} Slide from/to end(right) for enter transition, slide from/to
* start(left) for exit transition, shared element enter transition is set to ChangeBounds.
* <li> {@link #UI_STYLE_ENTRANCE} Enter transition is set to slide from both sides, exit
- * transition is same as {@link #UI_STYLE_DEFAULT}, no shared element enter transition.
+ * transition is same as {@link #UI_STYLE_REPLACE}, no shared element enter transition.
* <li> {@link #UI_STYLE_ACTIVITY_ROOT} Enter transition is set to null and app should rely on
- * activity transition, exit transition is same as {@link #UI_STYLE_DEFAULT}, no shared element
+ * activity transition, exit transition is same as {@link #UI_STYLE_REPLACE}, no shared element
* enter transition.
* </ul>
* <p>
@@ -775,7 +742,8 @@
*/
protected void onProvideFragmentTransitions() {
if (Build.VERSION.SDK_INT >= 21) {
- if (getUiStyle() == UI_STYLE_DEFAULT) {
+ final int uiStyle = getUiStyle();
+ if (uiStyle == UI_STYLE_REPLACE) {
Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END);
TransitionHelper.exclude(enterTransition, R.id.action_fragment_background, true);
TransitionHelper.exclude(enterTransition, R.id.guided_button_actions_background,
@@ -783,7 +751,32 @@
TransitionHelper.exclude(enterTransition, R.id.guided_button_actions_background2,
true);
TransitionHelper.exclude(enterTransition, R.id.guidedactions_selector, true);
+ TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
TransitionHelper.setEnterTransition(this, enterTransition);
+
+ // exit transition is unchanged, same as default UI_STYLE_ENTRANCE
+
+ Object changeBounds = TransitionHelper.createChangeBounds(false);
+ TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
+ } else if (uiStyle == UI_STYLE_ENTRANCE) {
+ Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
+ TransitionHelper.FADE_OUT);
+ TransitionHelper.include(fade, R.id.guidedstep_background);
+ Object slide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
+ Gravity.START);
+ TransitionHelper.include(slide, R.id.content_fragment);
+ TransitionHelper.include(slide, R.id.action_fragment_background);
+ TransitionHelper.include(slide, R.id.guided_button_actions_background);
+ TransitionHelper.include(slide, R.id.guidedactions_selector);
+ TransitionHelper.include(slide, R.id.guidedactions_list);
+ TransitionHelper.include(slide, R.id.guided_button_actions_background2);
+ TransitionHelper.include(slide, R.id.guidedactions_selector2);
+ TransitionHelper.include(slide, R.id.guidedactions_list2);
+ Object enterTransition = TransitionHelper.createTransitionSet(false);
+ TransitionHelper.addTransition(enterTransition, fade);
+ TransitionHelper.addTransition(enterTransition, slide);
+ TransitionHelper.setEnterTransition(this, enterTransition);
+
Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
TransitionHelper.exclude(exitTransition, R.id.action_fragment_background, true);
TransitionHelper.exclude(exitTransition, R.id.guided_button_actions_background,
@@ -792,118 +785,47 @@
TransitionHelper.exclude(exitTransition, R.id.guided_button_actions_background2,
true);
TransitionHelper.exclude(exitTransition, R.id.guidedactions_selector2, true);
+ TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
TransitionHelper.setExitTransition(this, exitTransition);
-
- Object changeBounds = TransitionHelper.createChangeBounds(false);
- TransitionHelper.setSharedElementEnterTransition(this, changeBounds);
- } else if (getUiStyle() == UI_STYLE_ENTRANCE) {
- Object enterTransition = TransitionHelper.createFadeAndShortSlide(Gravity.END |
- Gravity.START);
- TransitionHelper.include(enterTransition, R.id.content_fragment);
- TransitionHelper.include(enterTransition, R.id.action_fragment_background);
- TransitionHelper.include(enterTransition, R.id.guided_button_actions_background);
- TransitionHelper.include(enterTransition, R.id.guidedactions_selector);
- TransitionHelper.include(enterTransition, R.id.guidedactions_list);
- TransitionHelper.include(enterTransition, R.id.guided_button_actions_background2);
- TransitionHelper.include(enterTransition, R.id.guidedactions_selector2);
- TransitionHelper.include(enterTransition, R.id.guidedactions_list2);
- TransitionHelper.setEnterTransition(this, enterTransition);
- // exit transition is unchanged, same as UI_STYLE_DEFAULT
// No shared element transition
TransitionHelper.setSharedElementEnterTransition(this, null);
- } else if (getUiStyle() == UI_STYLE_ACTIVITY_ROOT) {
+ } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
// for Activity root, we dont need enter transition, use activity transition
TransitionHelper.setEnterTransition(this, null);
- // exit transition is unchanged, same as UI_STYLE_DEFAULT
+ // exit transition is unchanged, same as UI_STYLE_ENTRANCE
// No shared element transition
TransitionHelper.setSharedElementEnterTransition(this, null);
+ } else {
+ return;
}
}
}
/**
- * Default implementation of background for covering content below GuidedStepSupportFragment.
- * It uses current theme attribute guidedStepBackground which by default is read from
- * android:windowBackground.
+ * Called by onCreateView to inflate background view. Default implementation loads view
+ * from {@link R.layout#lb_guidedstep_background} which holds a reference to
+ * guidedStepBackground.
+ * @param inflater LayoutInflater to load background view.
+ * @param container Parent view of background view.
+ * @param savedInstanceState
+ * @return Created background view or null if no background.
*/
- public static class GuidedStepBackgroundSupportFragment extends Fragment {
- public GuidedStepBackgroundSupportFragment() {
- onProvideFragmentTransitions();
- }
-
- /**
- * Sets fragment transitions for GuidedStepBackgroundSupportFragment. Can be overridden.
- */
- protected void onProvideFragmentTransitions() {
- if (Build.VERSION.SDK_INT >= 21) {
- Object enterTransition = TransitionHelper.createFadeTransition(
- TransitionHelper.FADE_IN|TransitionHelper.FADE_OUT);
- TransitionHelper.setEnterTransition(this, enterTransition);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- FragmentActivity activity = getActivity();
- Context themedContext = null;
- if (!isGuidedStepTheme(activity)) {
- // Look up the guidedStepTheme in the activity's currently specified theme. If it
- // exists, replace the theme with its value.
- int resId = R.attr.guidedStepTheme;
- TypedValue typedValue = new TypedValue();
- boolean found = activity.getTheme().resolveAttribute(resId, typedValue, true);
- if (DEBUG) Log.v(TAG, "Found guided step theme reference? " + found);
- if (found) {
- ContextThemeWrapper themeWrapper =
- new ContextThemeWrapper(activity, typedValue.resourceId);
- if (isGuidedStepTheme(themeWrapper)) {
- themedContext = themeWrapper;
- }
- }
- if (!found) {
- Log.e(TAG, "GuidedStepSupportFragment does not have an appropriate theme set.");
- }
- }
-
- if (themedContext != null) {
- inflater = inflater.cloneInContext(themedContext);
- }
-
- return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
- }
+ public View onCreateBackgroundView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.lb_guidedstep_background, container, false);
}
/**
- * Creates a background fragment for {@link #UI_STYLE_ENTRANCE}, returns null for other cases.
- * Subclass may override the default behavior, e.g. provide different backgrounds
- * for {@link #UI_STYLE_DEFAULT}. Background fragment will be inserted in {@link
- * #getContainerIdForBackground()}.
+ * Set UI style to fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when fragment
+ * is first initialized. UI style is used to choose different fragment transition animations and
+ * determine if this is the first GuidedStepSupportFragment on backstack. In most cases app does not
+ * directly call this method, app calls helper function
+ * {@link #add(FragmentManager, GuidedStepSupportFragment, int)}. However if the app creates Fragment
+ * transaction and controls backstack by itself, it would need call setUiStyle() to select the
+ * fragment transition to use.
*
- * @return fragment that will be inserted below GuidedStepSupportFragment.
- */
- protected Fragment onProvideBackgroundSupportFragment() {
- if (getUiStyle() == UI_STYLE_ENTRANCE) {
- return new GuidedStepBackgroundSupportFragment();
- }
- return null;
- }
-
- /**
- * Returns container id for inserting {@link #onProvideBackgroundSupportFragment()}. The id should be
- * different than container id for inserting GuidedStepSupportFragment.
- * Default value is {@link View#NO_ID}. Subclass must override to host background fragment.
- * @return container id for inserting {@link #onProvideBackgroundSupportFragment()}
- */
- protected int getContainerIdForBackground() {
- return View.NO_ID;
- }
-
-
- /**
- * Set UI style to fragment arguments, UI style cannot be changed after initialization.
- * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_DEFAULT} or
- * {@link #UI_STYLE_ENTRANCE}.
+ * @param style {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
+ * {@link #UI_STYLE_ENTRANCE}.
*/
public void setUiStyle(int style) {
int oldStyle = getUiStyle();
@@ -924,15 +846,18 @@
}
/**
- * Read UI style from fragment arguments.
+ * Read UI style from fragment arguments. Default value is {@link #UI_STYLE_ENTRANCE} when
+ * fragment is first initialized. UI style is used to choose different fragment transition
+ * animations and determine if this is the first GuidedStepSupportFragment on backstack.
*
- * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_DEFAULT} or
+ * @return {@link #UI_STYLE_ACTIVITY_ROOT} {@link #UI_STYLE_REPLACE} or
* {@link #UI_STYLE_ENTRANCE}.
+ * @see #onProvideFragmentTransitions()
*/
public int getUiStyle() {
Bundle b = getArguments();
- if (b == null) return UI_STYLE_DEFAULT;
- return b.getInt(EXTRA_UI_STYLE, UI_STYLE_DEFAULT);
+ if (b == null) return UI_STYLE_ENTRANCE;
+ return b.getInt(EXTRA_UI_STYLE, UI_STYLE_ENTRANCE);
}
/**
@@ -966,6 +891,9 @@
mGuidanceStylist.onDestroyView();
mActionsStylist.onDestroyView();
mButtonActionsStylist.onDestroyView();
+ mAdapter = null;
+ mButtonAdapter = null;
+ mAdapterGroup = null;
super.onDestroyView();
}
@@ -980,9 +908,10 @@
resolveTheme();
inflater = getThemeInflater(inflater);
- View v = inflater.inflate(R.layout.lb_guidedstep_fragment, container, false);
- ViewGroup guidanceContainer = (ViewGroup) v.findViewById(R.id.content_fragment);
- ViewGroup actionContainer = (ViewGroup) v.findViewById(R.id.action_fragment);
+ ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_guidedstep_fragment,
+ container, false);
+ ViewGroup guidanceContainer = (ViewGroup) root.findViewById(R.id.content_fragment);
+ ViewGroup actionContainer = (ViewGroup) root.findViewById(R.id.action_fragment);
Guidance guidance = onCreateGuidance(savedInstanceState);
View guidanceView = mGuidanceStylist.onCreateView(inflater, guidanceContainer, guidance);
@@ -1013,10 +942,12 @@
}
};
- mAdapter = new GuidedActionAdapter(mActions, this, this, editListener,
- mActionsStylist);
- mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, editListener,
- mButtonActionsStylist);
+ mAdapter = new GuidedActionAdapter(mActions, this, this, mActionsStylist);
+ mButtonAdapter = new GuidedActionAdapter(mButtonActions, this, this, mButtonActionsStylist);
+ mAdapterGroup = new GuidedActionAdapterGroup();
+ mAdapterGroup.addAdpter(mAdapter);
+ mAdapterGroup.addAdpter(mButtonAdapter);
+ mAdapterGroup.setEditListener(editListener);
mActionsStylist.getActionsGridView().setAdapter(mAdapter);
mButtonActionsStylist.getActionsGridView().setAdapter(mButtonAdapter);
@@ -1034,7 +965,7 @@
TypedValue typedValue = new TypedValue();
if (ctx.getTheme().resolveAttribute(R.attr.guidedActionContentWidthWeightTwoPanels,
typedValue, true)) {
- View actionsRoot = v.findViewById(R.id.action_fragment_root);
+ View actionsRoot = root.findViewById(R.id.action_fragment_root);
float weight = typedValue.getFloat();
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) actionsRoot
.getLayoutParams();
@@ -1049,7 +980,11 @@
setSelectedButtonActionPosition(0);
- return v;
+ View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
+ if (backgroundView != null) {
+ root.addView(backgroundView, 0);
+ }
+ return root;
}
@Override
@@ -1081,6 +1016,8 @@
* Convenient method to close GuidedStepSupportFragments on top of other content or finish Activity if
* GuidedStepSupportFragments were started in a separate activity. Pops all stack entries including
* {@link #UI_STYLE_ENTRANCE}; if {@link #UI_STYLE_ENTRANCE} is not found, finish the activity.
+ * Note that this method must be paired with {@link #add(FragmentManager, GuidedStepSupportFragment,
+ * int)} which sets up the stack entry name for finding which fragment we need to pop back to.
*/
public void finishGuidedStepSupportFragments() {
final FragmentManager fragmentManager = getFragmentManager();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java b/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
new file mode 100644
index 0000000..627bbd4
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+import android.widget.ImageView;
+
+/**
+ * ImageView that supports Checkable states.
+ */
+class CheckableImageView extends ImageView implements Checkable {
+
+ private boolean mChecked;
+
+ private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
+
+ public CheckableImageView(Context context) {
+ this(context, null);
+ }
+
+ public CheckableImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CheckableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(final int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+
+ @Override
+ public void toggle() {
+ setChecked(!mChecked);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ @Override
+ public void setChecked(final boolean checked) {
+ if (mChecked != checked) {
+ mChecked = checked;
+ refreshDrawableState();
+ }
+ }
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index e7fa99f0..20d54e2 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -1773,6 +1773,11 @@
mFocusPositionOffset = 0;
saveContext(recycler, state);
+ View savedFocusView = findViewByPosition(mFocusPosition);
+ int savedFocusPos = mFocusPosition;
+ int savedSubFocusPos = mSubFocusPosition;
+ boolean hadFocus = mBaseGridView.hasFocus();
+
// Track the old focus view so we can adjust our system scroll position
// so that any scroll animations happening now will remain valid.
// We must use same delta in Pre Layout (if prelayout exists) and second layout.
@@ -1781,17 +1786,14 @@
if (mFocusPosition != NO_POSITION && scrollToFocus
&& mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
// FIXME: we should get the remaining scroll animation offset from RecyclerView
- View focusView = findViewByPosition(mFocusPosition);
- if (focusView != null) {
- if (getScrollPosition(focusView, focusView.findFocus(), sTwoInts)) {
+ if (savedFocusView != null) {
+ if (getScrollPosition(savedFocusView, savedFocusView.findFocus(), sTwoInts)) {
delta = sTwoInts[0];
deltaSecondary = sTwoInts[1];
}
}
}
- boolean hadFocus = mBaseGridView.hasFocus();
- int savedFocusPos = mFocusPosition;
if (mInFastRelayout = layoutInit()) {
fastRelayout();
// appends items till focus position.
@@ -1859,7 +1861,8 @@
}
// For fastRelayout, only dispatch event when focus position changes.
- if (mInFastRelayout && mFocusPosition != savedFocusPos) {
+ if (mInFastRelayout && (mFocusPosition != savedFocusPos || mSubFocusPosition !=
+ savedFocusPos || findViewByPosition(mFocusPosition) != savedFocusView)) {
dispatchChildSelected();
} else if (!mInFastRelayout && mInLayoutSearchFocus) {
// For full layout we dispatchChildSelected() in createItem() unless searched all
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 3485e93..3fcdbba 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
@@ -176,6 +176,10 @@
* Called when destroy the View created by GuidanceStylist.
*/
public void onDestroyView() {
+ mBreadcrumbView = null;
+ mDescriptionView = null;
+ mIconView = null;
+ mTitleView = null;
}
/**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
index 4031677..21986d5 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
@@ -37,8 +37,18 @@
private static final String TAG = "GuidedAction";
+ /**
+ * Special check set Id that is neither checkbox nor radio.
+ */
public static final int NO_CHECK_SET = 0;
+ /**
+ * Default checkset Id for radio.
+ */
public static final int DEFAULT_CHECK_SET_ID = 1;
+ /**
+ * Checkset Id for checkbox.
+ */
+ public static final int CHECKBOX_CHECK_SET_ID = -1;
/**
* When finishing editing, goes to next action.
@@ -371,10 +381,11 @@
}
/**
- * Indicates whether this action is part of a single-select group similar to radio buttons.
- * When one item in a check set is checked, all others with the same check set ID will be
- * unchecked automatically.
- * @param checkSetId The check set ID, or {@link #NO_CHECK_SET) to indicate no check set.
+ * Indicates whether this action is part of a single-select group similar to radio buttons
+ * or this action is a checkbox. When one item in a check set is checked, all others with
+ * the same check set ID will be nchecked automatically.
+ * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not
+ * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox.
*/
public Builder checkSetId(int checkSetId) {
mCheckSetId = checkSetId;
@@ -604,13 +615,13 @@
}
/**
- * Returns the check set id this action is a part of. All actions in the
- * same list with the same check set id are considered linked. When one
- * of the actions within that set is selected, that action becomes
- * checked, while all the other actions become unchecked.
+ * Returns the check set id this action is a part of. All actions in the same list with the same
+ * check set id are considered linked. When one of the actions within that set is selected, that
+ * action becomes checked, while all the other actions become unchecked.
*
* @return an integer representing the check set this action is a part of, or
- * {@link #NO_CHECK_SET} if this action isn't a part of a check set.
+ * {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if
+ * this action is not a checkbox or radiobutton.
*/
public int getCheckSetId() {
return mCheckSetId;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
index ab50399..8cdcdc8 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
@@ -27,6 +27,7 @@
import android.support.annotation.NonNull;
import android.support.v17.leanback.R;
import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -34,6 +35,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.animation.DecelerateInterpolator;
+import android.view.inputmethod.EditorInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -41,6 +43,7 @@
import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.widget.Checkable;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
@@ -101,8 +104,6 @@
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionCheckedAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUncheckedAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha
@@ -111,6 +112,8 @@
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines
* @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding
+ * @see android.R.styleable#Theme_listChoiceIndicatorSingle
+ * @see android.R.styleable#Theme_listChoiceIndicatorMultiple
* @see android.support.v17.leanback.app.GuidedStepFragment
* @see GuidedAction
*/
@@ -386,6 +389,10 @@
mActionsGridView.getViewTreeObserver().removeOnGlobalFocusChangeListener(
mGlobalFocusChangeListener);
}
+ mActionsGridView = null;
+ mSelectorView = null;
+ mBgView = null;
+ mMainView = null;
}
/**
@@ -515,14 +522,12 @@
vh.mDescriptionView.setFocusable(action.isDescriptionEditable());
}
// Clients might want the check mark view to be gone entirely, in which case, ignore it.
- if (vh.mCheckmarkView != null && vh.mCheckmarkView.getVisibility() != View.GONE) {
- vh.mCheckmarkView.setVisibility(action.isChecked() ? View.VISIBLE : View.INVISIBLE);
+ if (vh.mCheckmarkView != null) {
+ onBindCheckMarkView(vh, action);
}
if (vh.mChevronView != null) {
- vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.GONE);
- vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
- mDisabledChevronAlpha);
+ onBindChevronView(vh, action);
}
if (action.hasMultilineDescription()) {
@@ -553,6 +558,24 @@
((ViewGroup) vh.view).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
}
+ setupImeOptions(vh, action);
+ }
+
+ /**
+ * Called by {@link #onBindViewHolder(ViewHolder, GuidedAction)} to setup IME options. Default
+ * implementation assigns {@link EditorInfo#IME_ACTION_DONE}. Subclass may override.
+ * @param vh The view holder to be associated with the given action.
+ * @param action The guided action to be displayed by the view holder's view.
+ */
+ protected void setupImeOptions(ViewHolder vh, GuidedAction action) {
+ setupNextImeOptions(vh.getEditableTitleView());
+ setupNextImeOptions(vh.getEditableDescriptionView());
+ }
+
+ private void setupNextImeOptions(EditText edit) {
+ if (edit != null) {
+ edit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+ }
}
public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) {
@@ -640,31 +663,69 @@
}
/**
- * Animates the view holder's view (or subviews thereof) when the action has had its check
- * state changed.
+ * Animates the view holder's view (or subviews thereof) when the action has had its check state
+ * changed. Default implementation calls setChecked() if {@link ViewHolder#getCheckmarkView()}
+ * is instance of {@link Checkable}.
+ *
* @param vh The view holder associated with the relevant action.
* @param checked True if the action has become checked, false if it has become unchecked.
+ * @see #onBindCheckMarkView(ViewHolder, GuidedAction)
*/
public void onAnimateItemChecked(ViewHolder vh, boolean checked) {
- final View checkView = vh.mCheckmarkView;
- if (checkView != null) {
- if (checked) {
- checkView.setVisibility(View.VISIBLE);
- createAnimator(checkView, R.attr.guidedActionCheckedAnimation).start();
- } else {
- Animator animator = createAnimator(checkView,
- R.attr.guidedActionUncheckedAnimation);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- checkView.setVisibility(View.INVISIBLE);
- }
- });
- animator.start();
- }
+ if (vh.mCheckmarkView instanceof Checkable) {
+ ((Checkable) vh.mCheckmarkView).setChecked(checked);
}
}
+ /**
+ * Sets states of check mark view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}
+ * when action's checkset Id is other than {@link GuidedAction#NO_CHECK_SET}. Default
+ * implementation assigns drawable loaded from theme attribute
+ * {@link android.R.attr#listChoiceIndicatorMultiple} for checkbox or
+ * {@link android.R.attr#listChoiceIndicatorSingle} for radio button. Subclass rarely needs
+ * override the method, instead app can provide its own drawable that supports transition
+ * animations, change theme attributes {@link android.R.attr#listChoiceIndicatorMultiple} and
+ * {@link android.R.attr#listChoiceIndicatorSingle} in {android.support.v17.leanback.R.
+ * styleable#LeanbackGuidedStepTheme}.
+ *
+ * @param vh The view holder associated with the relevant action.
+ * @param action The GuidedAction object to bind to.
+ * @see #onAnimateItemChecked(ViewHolder, boolean)
+ */
+ public void onBindCheckMarkView(ViewHolder vh, GuidedAction action) {
+ if (action.getCheckSetId() != GuidedAction.NO_CHECK_SET) {
+ vh.mCheckmarkView.setVisibility(View.VISIBLE);
+ int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID ?
+ android.R.attr.listChoiceIndicatorMultiple :
+ android.R.attr.listChoiceIndicatorSingle;
+ final Context context = vh.mCheckmarkView.getContext();
+ Drawable drawable = null;
+ TypedValue typedValue = new TypedValue();
+ if (context.getTheme().resolveAttribute(attrId, typedValue, true)) {
+ drawable = ContextCompat.getDrawable(context, typedValue.resourceId);
+ }
+ vh.mCheckmarkView.setImageDrawable(drawable);
+ if (vh.mCheckmarkView instanceof Checkable) {
+ ((Checkable) vh.mCheckmarkView).setChecked(action.isChecked());
+ }
+ } else {
+ vh.mCheckmarkView.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets states of chevron view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}.
+ * Subclass may override.
+ *
+ * @param vh The view holder associated with the relevant action.
+ * @param action The GuidedAction object to bind to.
+ */
+ public void onBindChevronView(ViewHolder vh, GuidedAction action) {
+ vh.mChevronView.setVisibility(action.hasNext() ? View.VISIBLE : View.GONE);
+ vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
+ mDisabledChevronAlpha);
+ }
+
/*
* ==========================================
* FragmentAnimationProvider overrides
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java b/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
index 145ae48..902a665 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridActivity.java
@@ -360,7 +360,8 @@
holder.mItemAlignment = null;
}
if (mChildLayout == -1) {
- ((TextView) holder.itemView).setText("Item "+mItemLengths[position]);
+ ((TextView) holder.itemView).setText("Item "+mItemLengths[position]
+ + " type=" + getItemViewType(position));
boolean focusable = true;
if (mItemFocusables != null) {
focusable = mItemFocusables[position];
@@ -370,7 +371,8 @@
holder.itemView.setBackgroundColor(Color.LTGRAY);
} else {
if (holder.itemView instanceof TextView) {
- ((TextView) holder.itemView).setText("Item "+mItemLengths[position]);
+ ((TextView) holder.itemView).setText("Item "+mItemLengths[position]
+ + " type=" + getItemViewType(position));
}
}
updateSize(holder.itemView, position);
@@ -380,6 +382,7 @@
public int getItemCount() {
return mNumItems;
}
+
}
void updateSize(View view, int position) {
diff --git a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
index a24e1f6..335f449 100644
--- a/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/tests/src/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -21,6 +21,7 @@
import android.text.Spannable;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -1886,6 +1887,20 @@
}
}
+ static class ChangeableViewTypesProvider implements ViewTypeProvider {
+ static SparseIntArray sViewTypes = new SparseIntArray();
+ @Override
+ public int getViewType(int position) {
+ return sViewTypes.get(position);
+ }
+ public static void clear() {
+ sViewTypes.clear();
+ }
+ public static void setViewType(int position, int type) {
+ sViewTypes.put(position, type);
+ }
+ }
+
static class PositionItemAlignmentFacetProviderForRelativeLayout1
implements ItemAlignmentFacetProvider {
ItemAlignmentFacet mMultipleFacet;
@@ -2101,6 +2116,38 @@
assertEquals(0, mGridView.getSelectedPosition());
}
+ public void testNotifyItemTypeChangedSelectionEvent() throws Throwable {
+ mInstrumentation = getInstrumentation();
+ Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+ intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+ R.layout.vertical_linear);
+ intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+ intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+ ChangeableViewTypesProvider.class.getName());
+ ChangeableViewTypesProvider.clear();
+ initActivity(intent);
+ mOrientation = BaseGridView.HORIZONTAL;
+ mNumRows = 1;
+
+ final ArrayList<Integer> selectedLog = new ArrayList<Integer>();
+ mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+ public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+ selectedLog.add(position);
+ }
+ });
+
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ ChangeableViewTypesProvider.setViewType(0, 1);
+ mGridView.getAdapter().notifyItemChanged(0, 1);
+ }
+ });
+ waitForTransientStateGone(null);
+ assertEquals(0, mGridView.getSelectedPosition());
+ assertEquals(selectedLog.size(), 1);
+ assertEquals((int) selectedLog.get(0), 0);
+ }
+
public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable {
mInstrumentation = getInstrumentation();
Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
diff --git a/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java b/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
index 4bea5d9..fe988fe 100644
--- a/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
+++ b/v4/api21/android/service/media/IMediaBrowserServiceCallbacks.java
@@ -18,8 +18,11 @@
import android.content.pm.ParceledListSlice;
import android.media.session.MediaSession;
+import android.os.Binder;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.IInterface;
+import android.os.Parcel;
import android.os.RemoteException;
/**
@@ -30,6 +33,56 @@
* @hide
*/
public interface IMediaBrowserServiceCallbacks extends IInterface {
+ public static abstract class Stub extends Binder implements IMediaBrowserServiceCallbacks
+ {
+ public Stub() {
+ }
+
+ public static IMediaBrowserServiceCallbacks asInterface(IBinder obj) {
+ return null;
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ return false;
+ }
+
+ private static class Proxy implements IMediaBrowserServiceCallbacks
+ {
+ Proxy(IBinder remote) {
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ public String getInterfaceDescriptor() {
+ return null;
+ }
+
+ @Override
+ public void onConnect(String root, MediaSession.Token session, Bundle extras)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onConnectFailed() throws RemoteException {
+ }
+
+ @Override
+ public void onLoadChildren(String mediaId, ParceledListSlice list)
+ throws RemoteException {
+ }
+ }
+ }
+
public void onConnect(String root, MediaSession.Token session, Bundle extras)
throws RemoteException;
public void onConnectFailed() throws RemoteException;
diff --git a/v4/java/android/support/v4/view/PagerAdapter.java b/v4/java/android/support/v4/view/PagerAdapter.java
index ef52404..55fb9c1 100644
--- a/v4/java/android/support/v4/view/PagerAdapter.java
+++ b/v4/java/android/support/v4/view/PagerAdapter.java
@@ -76,7 +76,8 @@
* the method {@link #getItemPosition(Object)}.</p>
*/
public abstract class PagerAdapter {
- private DataSetObservable mObservable = new DataSetObservable();
+ private final DataSetObservable mObservable = new DataSetObservable();
+ private DataSetObserver mViewPagerObserver;
public static final int POSITION_UNCHANGED = -1;
public static final int POSITION_NONE = -2;
@@ -273,6 +274,11 @@
* and associated views should update.
*/
public void notifyDataSetChanged() {
+ synchronized (this) {
+ if (mViewPagerObserver != null) {
+ mViewPagerObserver.onChanged();
+ }
+ }
mObservable.notifyChanged();
}
@@ -294,6 +300,12 @@
mObservable.unregisterObserver(observer);
}
+ void setViewPagerObserver(DataSetObserver observer) {
+ synchronized (this) {
+ mViewPagerObserver = observer;
+ }
+ }
+
/**
* This method may be called by the ViewPager to obtain a title string
* to describe the specified page. This method may return null
diff --git a/v4/java/android/support/v4/view/ViewPager.java b/v4/java/android/support/v4/view/ViewPager.java
index 454ac62..c6f3648 100644
--- a/v4/java/android/support/v4/view/ViewPager.java
+++ b/v4/java/android/support/v4/view/ViewPager.java
@@ -418,7 +418,7 @@
*/
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
- mAdapter.unregisterDataSetObserver(mObserver);
+ mAdapter.setViewPagerObserver(null);
mAdapter.startUpdate(this);
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
@@ -439,7 +439,7 @@
if (mObserver == null) {
mObserver = new PagerObserver();
}
- mAdapter.registerDataSetObserver(mObserver);
+ mAdapter.setViewPagerObserver(mObserver);
mPopulatePending = false;
final boolean wasFirstLayout = mFirstLayout;
mFirstLayout = true;
diff --git a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
index d2c7b91..e147b7d 100644
--- a/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
+++ b/v7/appcompat/src/android/support/v7/app/AppCompatDelegateImplV7.java
@@ -115,6 +115,8 @@
private PanelFeatureState[] mPanels;
private PanelFeatureState mPreparedPanel;
+ private boolean mLongPressBackDown;
+
private boolean mInvalidatePanelMenuPosted;
private int mInvalidatePanelMenuFeatures;
private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
@@ -874,9 +876,17 @@
onKeyUpPanel(Window.FEATURE_OPTIONS_PANEL, event);
return true;
case KeyEvent.KEYCODE_BACK:
+ final boolean wasLongPressBackDown = mLongPressBackDown;
+ mLongPressBackDown = false;
+
PanelFeatureState st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
if (st != null && st.isOpen) {
- closePanel(st, true);
+ if (!wasLongPressBackDown) {
+ // Certain devices allow opening the options menu via a long press of the
+ // back button. We should only close the open options menu if it wasn't
+ // opened via a long press gesture.
+ closePanel(st, true);
+ }
return true;
}
if (onBackPressed()) {
@@ -895,6 +905,11 @@
// For empty menus, PhoneWindow's KEYCODE_BACK handling will steals all events,
// not allowing the Activity to call onBackPressed().
return true;
+ case KeyEvent.KEYCODE_BACK:
+ // Certain devices allow opening the options menu via a long press of the back
+ // button. We keep a record of whether the last event is from a long press.
+ mLongPressBackDown = (event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
+ break;
}
// On API v7-10 we need to manually call onKeyShortcut() as this is not called
diff --git a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
index eb04b01..89deb68 100644
--- a/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/android/support/v7/widget/AppCompatDrawableManager.java
@@ -663,7 +663,7 @@
return getPorterDuffColorFilter(color, tintMode);
}
- private static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
+ public static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
// First, lets see if the cache already contains the color filter
PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
index 9beb8d9..8e5e2c6 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
@@ -28,7 +28,6 @@
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
-import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.support.v7.mediarouter.R;
@@ -65,9 +64,6 @@
public class MediaRouteChooserDialog extends Dialog {
private static final String TAG = "MediaRouteChooserDialog";
- // Should match to SystemMediaRouteProvider.PACKAGE_NAME.
- static final String SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME = "android";
-
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
@@ -322,7 +318,7 @@
// Only speakers can be grouped for now.
return mSpeakerGroupIcon;
}
- if (isSystemLiveAudioOnlyRoute(route)) {
+ if (route.isDeviceTypeBluetooth()) {
return mBluetoothIcon;
}
return mDefaultIcon;
@@ -365,11 +361,16 @@
@Override
public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
- if (isSystemLiveAudioOnlyRoute(lhs)) {
- if (!isSystemLiveAudioOnlyRoute(rhs)) {
+ if (lhs == null) {
+ return rhs == null ? 0 : -1;
+ } else if (rhs == null) {
+ return 1;
+ }
+ if (lhs.isDeviceTypeBluetooth()) {
+ if (!rhs.isDeviceTypeBluetooth()) {
return 1;
}
- } else if (isSystemLiveAudioOnlyRoute(rhs)) {
+ } else if (rhs.isDeviceTypeBluetooth()) {
return -1;
}
Float lhsUsageScore = sRouteUsageScoreMap.get(lhs.getId());
@@ -430,17 +431,4 @@
prefEditor.commit();
}
}
-
- // Used to determine whether the route represents a bluetooth device.
- // TODO: Find a better way to precisely detect bluetooth routes.
- private static boolean isSystemLiveAudioOnlyRoute(MediaRouter.RouteInfo route) {
- return isSystemMediaRouteProvider(route)
- && route.supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
- && !route.supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO);
- }
-
- private static boolean isSystemMediaRouteProvider(MediaRouter.RouteInfo route) {
- return TextUtils.equals(route.getProviderInstance().getMetadata().getPackageName(),
- SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME);
- }
}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index 537b382..547daa7d 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -37,7 +37,6 @@
import android.support.v4.media.session.PlaybackStateCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v7.graphics.Palette;
-import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.support.v7.mediarouter.R;
@@ -319,12 +318,12 @@
if (pi != null) {
try {
pi.send();
+ dismiss();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, pi + " was not sent, it had been canceled.");
}
}
}
- dismiss();
}
};
mArtView = (ImageView) findViewById(R.id.mr_art);
@@ -467,14 +466,7 @@
}
private boolean canShowPlaybackControlLayout() {
- // If a route does not support remote playback, it means that the route is dedicated for
- // audio or video streaming such as A2DP speaker or headset. In this case, the route
- // provider does not provide any playback information such as metadata or playback status.
- // But, for live video, playback control UI shows a message that the screen is being
- // mirrored, while it does not show anything for live audio.
- return mCustomControlView == null && (mDescription != null || mState != null)
- && (mRoute.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
- || mRoute.supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO));
+ return mCustomControlView == null && (mDescription != null || mState != null);
}
/**
@@ -718,8 +710,12 @@
mTitleView.setText(R.string.mr_controller_casting_screen);
showTitle = true;
} else if (mState == null || mState.getState() == PlaybackStateCompat.STATE_NONE) {
- mTitleView.setText(R.string.mr_controller_no_media_selected);
- showTitle = true;
+ // Show "No media selected" as we don't yet know the playback state.
+ // (Only exception is bluetooth where we don't show anything.)
+ if (!mRoute.isDeviceTypeBluetooth()) {
+ mTitleView.setText(R.string.mr_controller_no_media_selected);
+ showTitle = true;
+ }
} else if (!hasTitle && !hasSubtitle) {
mTitleView.setText(R.string.mr_controller_no_info_available);
showTitle = true;
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index 18bcc85..b2e74e4 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -40,6 +40,7 @@
import android.support.v4.util.Pair;
import android.support.v7.media.MediaRouteProvider.ProviderMetadata;
import android.support.v7.media.MediaRouteProvider.RouteController;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
@@ -913,6 +914,9 @@
static final int CHANGE_VOLUME = 1 << 1;
static final int CHANGE_PRESENTATION_DISPLAY = 1 << 2;
+ // Should match to SystemMediaRouteProvider.PACKAGE_NAME.
+ static final String SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME = "android";
+
RouteInfo(ProviderInfo provider, String descriptorId, String uniqueId) {
mProvider = provider;
mDescriptorId = descriptorId;
@@ -1226,6 +1230,33 @@
return mDeviceType;
}
+
+ /**
+ * Gets whether the type of the receiver device associated with this route is
+ * {@link #DEVICE_TYPE_BLUETOOTH}.
+ * <p>
+ * This is a workaround for platform version 23 or below where the system route provider
+ * doesn't specify device type for bluetooth media routes.
+ * </p>
+ *
+ * @return True if the receiver device type can be assumed to be
+ * {@link #DEVICE_TYPE_BLUETOOTH}, false otherwise.
+ * @hide
+ */
+ public boolean isDeviceTypeBluetooth() {
+ if (mDeviceType == DEVICE_TYPE_BLUETOOTH) {
+ return true;
+ }
+ return isSystemMediaRouteProvider(this)
+ && supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
+ && !supportsControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO);
+ }
+
+ private static boolean isSystemMediaRouteProvider(MediaRouter.RouteInfo route) {
+ return TextUtils.equals(route.getProviderInstance().getMetadata().getPackageName(),
+ SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME);
+ }
+
/**
* Gets information about how volume is handled on the route.
*
diff --git a/v7/palette/api/current.txt b/v7/palette/api/current.txt
index fac6a55..3b24b77 100644
--- a/v7/palette/api/current.txt
+++ b/v7/palette/api/current.txt
@@ -7,6 +7,7 @@
method public static deprecated android.support.v7.graphics.Palette generate(android.graphics.Bitmap, int);
method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, android.support.v7.graphics.Palette.PaletteAsyncListener);
method public static deprecated android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generateAsync(android.graphics.Bitmap, int, android.support.v7.graphics.Palette.PaletteAsyncListener);
+ method public int getColorForTarget(android.support.v7.graphics.Target, int);
method public int getDarkMutedColor(int);
method public android.support.v7.graphics.Palette.Swatch getDarkMutedSwatch();
method public int getDarkVibrantColor(int);
@@ -17,7 +18,9 @@
method public android.support.v7.graphics.Palette.Swatch getLightVibrantSwatch();
method public int getMutedColor(int);
method public android.support.v7.graphics.Palette.Swatch getMutedSwatch();
+ method public android.support.v7.graphics.Palette.Swatch getSwatchForTarget(android.support.v7.graphics.Target);
method public java.util.List<android.support.v7.graphics.Palette.Swatch> getSwatches();
+ method public java.util.List<android.support.v7.graphics.Target> getTargets();
method public int getVibrantColor(int);
method public android.support.v7.graphics.Palette.Swatch getVibrantSwatch();
}
@@ -26,12 +29,15 @@
ctor public Palette.Builder(android.graphics.Bitmap);
ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+ method public android.support.v7.graphics.Palette.Builder addTarget(android.support.v7.graphics.Target);
method public android.support.v7.graphics.Palette.Builder clearFilters();
method public android.support.v7.graphics.Palette.Builder clearRegion();
+ method public android.support.v7.graphics.Palette.Builder clearTargets();
method public android.support.v7.graphics.Palette generate();
method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
- method public android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
+ method public android.support.v7.graphics.Palette.Builder resizeBitmapArea(int);
+ method public deprecated android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
method public android.support.v7.graphics.Palette.Builder setRegion(int, int, int, int);
}
@@ -52,5 +58,40 @@
method public int getTitleTextColor();
}
+ public final class Target {
+ method public float getLightnessWeight();
+ method public float getMaximumLightness();
+ method public float getMaximumSaturation();
+ method public float getMinimumLightness();
+ method public float getMinimumSaturation();
+ method public float getPopulationWeight();
+ method public float getSaturationWeight();
+ method public float getTargetLightness();
+ method public float getTargetSaturation();
+ method public boolean isExclusive();
+ field public static final android.support.v7.graphics.Target DARK_MUTED;
+ field public static final android.support.v7.graphics.Target DARK_VIBRANT;
+ field public static final android.support.v7.graphics.Target LIGHT_MUTED;
+ field public static final android.support.v7.graphics.Target LIGHT_VIBRANT;
+ field public static final android.support.v7.graphics.Target MUTED;
+ field public static final android.support.v7.graphics.Target VIBRANT;
+ }
+
+ public static final class Target.Builder {
+ ctor public Target.Builder();
+ ctor public Target.Builder(android.support.v7.graphics.Target);
+ method public android.support.v7.graphics.Target build();
+ method public android.support.v7.graphics.Target.Builder setExclusive(boolean);
+ method public android.support.v7.graphics.Target.Builder setLightnessWeight(float);
+ method public android.support.v7.graphics.Target.Builder setMaximumLightness(float);
+ method public android.support.v7.graphics.Target.Builder setMaximumSaturation(float);
+ method public android.support.v7.graphics.Target.Builder setMinimumLightness(float);
+ method public android.support.v7.graphics.Target.Builder setMinimumSaturation(float);
+ method public android.support.v7.graphics.Target.Builder setPopulationWeight(float);
+ method public android.support.v7.graphics.Target.Builder setSaturationWeight(float);
+ method public android.support.v7.graphics.Target.Builder setTargetLightness(float);
+ method public android.support.v7.graphics.Target.Builder setTargetSaturation(float);
+ }
+
}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java b/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java
deleted file mode 100644
index 3ee2bfa..0000000
--- a/v7/palette/src/main/java/android/support/v7/graphics/DefaultGenerator.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.graphics;
-
-import android.support.v4.graphics.ColorUtils;
-import android.support.v7.graphics.Palette.Swatch;
-
-import java.util.List;
-
-class DefaultGenerator extends Palette.Generator {
-
- private static final float TARGET_DARK_LUMA = 0.26f;
- private static final float MAX_DARK_LUMA = 0.45f;
-
- private static final float MIN_LIGHT_LUMA = 0.55f;
- private static final float TARGET_LIGHT_LUMA = 0.74f;
-
- private static final float MIN_NORMAL_LUMA = 0.3f;
- private static final float TARGET_NORMAL_LUMA = 0.5f;
- private static final float MAX_NORMAL_LUMA = 0.7f;
-
- private static final float TARGET_MUTED_SATURATION = 0.3f;
- private static final float MAX_MUTED_SATURATION = 0.4f;
-
- private static final float TARGET_VIBRANT_SATURATION = 1f;
- private static final float MIN_VIBRANT_SATURATION = 0.35f;
-
- private static final float WEIGHT_SATURATION = 3f;
- private static final float WEIGHT_LUMA = 6f;
- private static final float WEIGHT_POPULATION = 1f;
-
- private List<Swatch> mSwatches;
-
- private int mHighestPopulation;
-
- private Swatch mVibrantSwatch;
- private Swatch mMutedSwatch;
- private Swatch mDarkVibrantSwatch;
- private Swatch mDarkMutedSwatch;
- private Swatch mLightVibrantSwatch;
- private Swatch mLightMutedSwatch;
-
- @Override
- public void generate(final List<Swatch> swatches) {
- mSwatches = swatches;
-
- mHighestPopulation = findMaxPopulation();
-
- generateVariationColors();
-
- // Now try and generate any missing colors
- generateEmptySwatches();
- }
-
- @Override
- public Swatch getVibrantSwatch() {
- return mVibrantSwatch;
- }
-
- @Override
- public Swatch getLightVibrantSwatch() {
- return mLightVibrantSwatch;
- }
-
- @Override
- public Swatch getDarkVibrantSwatch() {
- return mDarkVibrantSwatch;
- }
-
- @Override
- public Swatch getMutedSwatch() {
- return mMutedSwatch;
- }
-
- @Override
- public Swatch getLightMutedSwatch() {
- return mLightMutedSwatch;
- }
-
- @Override
- public Swatch getDarkMutedSwatch() {
- return mDarkMutedSwatch;
- }
-
- private void generateVariationColors() {
- mVibrantSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
- TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
- mLightVibrantSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
- TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
- mDarkVibrantSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
- TARGET_VIBRANT_SATURATION, MIN_VIBRANT_SATURATION, 1f);
-
- mMutedSwatch = findColorVariation(TARGET_NORMAL_LUMA, MIN_NORMAL_LUMA, MAX_NORMAL_LUMA,
- TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-
- mLightMutedSwatch = findColorVariation(TARGET_LIGHT_LUMA, MIN_LIGHT_LUMA, 1f,
- TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
-
- mDarkMutedSwatch = findColorVariation(TARGET_DARK_LUMA, 0f, MAX_DARK_LUMA,
- TARGET_MUTED_SATURATION, 0f, MAX_MUTED_SATURATION);
- }
-
- /**
- * Try and generate any missing swatches from the swatches we did find.
- */
- private void generateEmptySwatches() {
- if (mVibrantSwatch == null) {
- // If we do not have a vibrant color...
- if (mDarkVibrantSwatch != null) {
- // ...but we do have a dark vibrant, generate the value by modifying the luma
- final float[] newHsl = copyHslValues(mDarkVibrantSwatch);
- newHsl[2] = TARGET_NORMAL_LUMA;
- mVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
- }
- }
-
- if (mDarkVibrantSwatch == null) {
- // If we do not have a dark vibrant color...
- if (mVibrantSwatch != null) {
- // ...but we do have a vibrant, generate the value by modifying the luma
- final float[] newHsl = copyHslValues(mVibrantSwatch);
- newHsl[2] = TARGET_DARK_LUMA;
- mDarkVibrantSwatch = new Swatch(ColorUtils.HSLToColor(newHsl), 0);
- }
- }
- }
-
- /**
- * Find the {@link Palette.Swatch} with the highest population value and return the population.
- */
- private int findMaxPopulation() {
- int population = 0;
- for (Swatch swatch : mSwatches) {
- population = Math.max(population, swatch.getPopulation());
- }
- return population;
- }
-
- private Swatch findColorVariation(float targetLuma, float minLuma, float maxLuma,
- float targetSaturation, float minSaturation, float maxSaturation) {
- Swatch max = null;
- float maxValue = 0f;
-
- for (Swatch swatch : mSwatches) {
- final float sat = swatch.getHsl()[1];
- final float luma = swatch.getHsl()[2];
-
- if (sat >= minSaturation && sat <= maxSaturation &&
- luma >= minLuma && luma <= maxLuma &&
- !isAlreadySelected(swatch)) {
- float value = createComparisonValue(sat, targetSaturation, luma, targetLuma,
- swatch.getPopulation(), mHighestPopulation);
- if (max == null || value > maxValue) {
- max = swatch;
- maxValue = value;
- }
- }
- }
-
- return max;
- }
-
- /**
- * @return true if we have already selected {@code swatch}
- */
- private boolean isAlreadySelected(Swatch swatch) {
- return mVibrantSwatch == swatch || mDarkVibrantSwatch == swatch ||
- mLightVibrantSwatch == swatch || mMutedSwatch == swatch ||
- mDarkMutedSwatch == swatch || mLightMutedSwatch == swatch;
- }
-
- private static float createComparisonValue(float saturation, float targetSaturation,
- float luma, float targetLuma,
- int population, int maxPopulation) {
- return createComparisonValue(saturation, targetSaturation, WEIGHT_SATURATION,
- luma, targetLuma, WEIGHT_LUMA,
- population, maxPopulation, WEIGHT_POPULATION);
- }
-
- private static float createComparisonValue(
- float saturation, float targetSaturation, float saturationWeight,
- float luma, float targetLuma, float lumaWeight,
- int population, int maxPopulation, float populationWeight) {
- return weightedMean(
- invertDiff(saturation, targetSaturation), saturationWeight,
- invertDiff(luma, targetLuma), lumaWeight,
- population / (float) maxPopulation, populationWeight
- );
- }
-
- /**
- * Copy a {@link Swatch}'s HSL values into a new float[].
- */
- private static float[] copyHslValues(Swatch color) {
- final float[] newHsl = new float[3];
- System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
- return newHsl;
- }
-
- /**
- * Returns a value in the range 0-1. 1 is returned when {@code value} equals the
- * {@code targetValue} and then decreases as the absolute difference between {@code value} and
- * {@code targetValue} increases.
- *
- * @param value the item's value
- * @param targetValue the value which we desire
- */
- private static float invertDiff(float value, float targetValue) {
- return 1f - Math.abs(value - targetValue);
- }
-
- private static float weightedMean(float... values) {
- float sum = 0f;
- float sumWeight = 0f;
-
- for (int i = 0; i < values.length; i += 2) {
- float value = values[i];
- float weight = values[i + 1];
-
- sum += (value * weight);
- sumWeight += weight;
- }
-
- return sum / sumWeight;
- }
-}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index 57f34a6..d0dff30 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -21,16 +21,20 @@
import android.graphics.Rect;
import android.os.AsyncTask;
import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.os.AsyncTaskCompat;
+import android.support.v4.util.ArrayMap;
import android.util.Log;
+import android.util.SparseBooleanArray;
import android.util.TimingLogger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* A helper class to extract prominent colors from an image.
@@ -80,7 +84,7 @@
void onGenerated(Palette palette);
}
- private static final int DEFAULT_RESIZE_BITMAP_MAX_DIMENSION = 192;
+ private static final int DEFAULT_RESIZE_BITMAP_AREA = 160 * 160;
private static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
private static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
@@ -140,151 +144,266 @@
}
private final List<Swatch> mSwatches;
- private final Generator mGenerator;
+ private final List<Target> mTargets;
- private Palette(List<Swatch> swatches, Generator generator) {
+ private final Map<Target, Swatch> mSelectedSwatches;
+ private final SparseBooleanArray mUsedColors;
+
+ private final int mMaxPopulation;
+
+ private Palette(List<Swatch> swatches, List<Target> targets) {
mSwatches = swatches;
- mGenerator = generator;
+ mTargets = targets;
+
+ mUsedColors = new SparseBooleanArray();
+ mSelectedSwatches = new ArrayMap<>();
+
+ mMaxPopulation = findMaxPopulation();
}
/**
* Returns all of the swatches which make up the palette.
*/
+ @NonNull
public List<Swatch> getSwatches() {
return Collections.unmodifiableList(mSwatches);
}
/**
+ * Returns the targets used to generate this palette.
+ */
+ @NonNull
+ public List<Target> getTargets() {
+ return Collections.unmodifiableList(mTargets);
+ }
+
+ /**
* Returns the most vibrant swatch in the palette. Might be null.
+ *
+ * @see Target#VIBRANT
*/
@Nullable
public Swatch getVibrantSwatch() {
- return mGenerator.getVibrantSwatch();
+ return getSwatchForTarget(Target.VIBRANT);
}
/**
* Returns a light and vibrant swatch from the palette. Might be null.
+ *
+ * @see Target#LIGHT_VIBRANT
*/
@Nullable
public Swatch getLightVibrantSwatch() {
- return mGenerator.getLightVibrantSwatch();
+ return getSwatchForTarget(Target.LIGHT_VIBRANT);
}
/**
* Returns a dark and vibrant swatch from the palette. Might be null.
+ *
+ * @see Target#DARK_VIBRANT
*/
@Nullable
public Swatch getDarkVibrantSwatch() {
- return mGenerator.getDarkVibrantSwatch();
+ return getSwatchForTarget(Target.DARK_VIBRANT);
}
/**
* Returns a muted swatch from the palette. Might be null.
+ *
+ * @see Target#MUTED
*/
@Nullable
public Swatch getMutedSwatch() {
- return mGenerator.getMutedSwatch();
+ return getSwatchForTarget(Target.MUTED);
}
/**
* Returns a muted and light swatch from the palette. Might be null.
+ *
+ * @see Target#LIGHT_MUTED
*/
@Nullable
public Swatch getLightMutedSwatch() {
- return mGenerator.getLightMutedSwatch();
+ return getSwatchForTarget(Target.LIGHT_MUTED);
}
/**
* Returns a muted and dark swatch from the palette. Might be null.
+ *
+ * @see Target#DARK_MUTED
*/
@Nullable
public Swatch getDarkMutedSwatch() {
- return mGenerator.getDarkMutedSwatch();
+ return getSwatchForTarget(Target.DARK_MUTED);
}
/**
* Returns the most vibrant color in the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getVibrantSwatch()
*/
@ColorInt
- public int getVibrantColor(@ColorInt int defaultColor) {
- Swatch swatch = getVibrantSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.VIBRANT, defaultColor);
}
/**
* Returns a light and vibrant color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getLightVibrantSwatch()
*/
@ColorInt
- public int getLightVibrantColor(@ColorInt int defaultColor) {
- Swatch swatch = getLightVibrantSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getLightVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.LIGHT_VIBRANT, defaultColor);
}
/**
* Returns a dark and vibrant color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getDarkVibrantSwatch()
*/
@ColorInt
- public int getDarkVibrantColor(@ColorInt int defaultColor) {
- Swatch swatch = getDarkVibrantSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getDarkVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.DARK_VIBRANT, defaultColor);
}
/**
* Returns a muted color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getMutedSwatch()
*/
@ColorInt
- public int getMutedColor(@ColorInt int defaultColor) {
- Swatch swatch = getMutedSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.MUTED, defaultColor);
}
/**
* Returns a muted and light color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getLightMutedSwatch()
*/
@ColorInt
- public int getLightMutedColor(@ColorInt int defaultColor) {
- Swatch swatch = getLightMutedSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getLightMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.LIGHT_MUTED, defaultColor);
}
/**
* Returns a muted and dark color from the palette as an RGB packed int.
*
* @param defaultColor value to return if the swatch isn't available
+ * @see #getDarkMutedSwatch()
*/
@ColorInt
- public int getDarkMutedColor(@ColorInt int defaultColor) {
- Swatch swatch = getDarkMutedSwatch();
- return swatch != null ? swatch.getRgb() : defaultColor;
+ public int getDarkMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.DARK_MUTED, defaultColor);
}
/**
- * Scale the bitmap down so that it's largest dimension is {@code targetMaxDimension}.
- * If {@code bitmap} is smaller than this, then it is returned.
+ * Returns the selected swatch for the given target from the palette, or {@code null} if one
+ * could not be found.
*/
- private static Bitmap scaleBitmapDown(Bitmap bitmap, final int targetMaxDimension) {
- final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+ @Nullable
+ public Swatch getSwatchForTarget(@NonNull final Target target) {
+ return mSelectedSwatches.get(target);
+ }
- if (maxDimension <= targetMaxDimension) {
- // If the bitmap is small enough already, just return it
- return bitmap;
+ /**
+ * Returns the selected color for the given target from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {
+ Swatch swatch = getSwatchForTarget(target);
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ private void generate() {
+ // We need to make sure that the scored targets are generated first. This is so that
+ // inherited targets have something to inherit from
+ for (int i = 0, count = mTargets.size(); i < count; i++) {
+ final Target target = mTargets.get(i);
+ target.normalizeWeights();
+ mSelectedSwatches.put(target, generateScoredTarget(target));
+ }
+ // We now clear out the used colors
+ mUsedColors.clear();
+ }
+
+ private Swatch generateScoredTarget(final Target target) {
+ final Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
+ if (maxScoreSwatch != null && target.isExclusive()) {
+ // If we have a swatch, and the target is exclusive, add the color to the used list
+ mUsedColors.append(maxScoreSwatch.getRgb(), true);
+ }
+ return maxScoreSwatch;
+ }
+
+ private Swatch getMaxScoredSwatchForTarget(final Target target) {
+ float maxScore = 0;
+ Swatch maxScoreSwatch = null;
+ for (int i = 0, count = mSwatches.size(); i < count; i++) {
+ final Swatch swatch = mSwatches.get(i);
+ if (shouldBeScoredForTarget(swatch, target)) {
+ final float score = generateScore(swatch, target);
+ if (maxScoreSwatch == null || score > maxScore) {
+ maxScoreSwatch = swatch;
+ maxScore = score;
+ }
+ }
+ }
+ return maxScoreSwatch;
+ }
+
+ private boolean shouldBeScoredForTarget(final Swatch swatch, final Target target) {
+ // Check whether the HSL values are within the correct ranges, and this color hasn't
+ // been used yet.
+ final float hsl[] = swatch.getHsl();
+ return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
+ && hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
+ && !mUsedColors.get(swatch.getRgb());
+ }
+
+ private float generateScore(Swatch swatch, Target target) {
+ final float[] hsl = swatch.getHsl();
+
+ float saturationScore = 0;
+ float luminanceScore = 0;
+ float populationScore = 0;
+
+ if (target.getSaturationWeight() > 0) {
+ saturationScore = target.getSaturationWeight()
+ * (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
+ }
+ if (target.getLightnessWeight() > 0) {
+ luminanceScore = target.getLightnessWeight()
+ * (1f - Math.abs(hsl[2] - target.getTargetLightness()));
+ }
+ if (target.getPopulationWeight() > 0) {
+ populationScore = target.getPopulationWeight()
+ * (swatch.getPopulation() / (float) mMaxPopulation);
}
- final double scaleRatio = targetMaxDimension / (double) maxDimension;
- return Bitmap.createScaledBitmap(bitmap,
- (int) Math.ceil(bitmap.getWidth() * scaleRatio),
- (int) Math.ceil(bitmap.getHeight() * scaleRatio),
- false);
+ return saturationScore + luminanceScore + populationScore;
+ }
+
+ private int findMaxPopulation() {
+ int max = 0;
+ for (int i = 0, count = mSwatches.size(); i < count; i++) {
+ max = Math.max(mSwatches.get(i).getPopulation(), max);
+ }
+ return max;
+ }
+
+ private static float[] copyHslValues(Swatch color) {
+ final float[] newHsl = new float[3];
+ System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
+ return newHsl;
}
/**
@@ -318,6 +437,11 @@
mPopulation = population;
}
+ Swatch(float[] hsl, int population) {
+ this(ColorUtils.HSLToColor(hsl), population);
+ mHsl = hsl;
+ }
+
/**
* @return this swatch's RGB color value
*/
@@ -335,8 +459,8 @@
public float[] getHsl() {
if (mHsl == null) {
mHsl = new float[3];
- ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
}
+ ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
return mHsl;
}
@@ -445,13 +569,16 @@
public static final class Builder {
private final List<Swatch> mSwatches;
private final Bitmap mBitmap;
+
+ private final List<Target> mTargets = new ArrayList<>();
+
private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
- private int mResizeMaxDimension = DEFAULT_RESIZE_BITMAP_MAX_DIMENSION;
+ private int mResizeArea = DEFAULT_RESIZE_BITMAP_AREA;
+ private int mResizeMaxDimension = -1;
+
private final List<Filter> mFilters = new ArrayList<>();
private Rect mRegion;
- private Generator mGenerator;
-
/**
* Construct a new {@link Builder} using a source {@link Bitmap}
*/
@@ -462,6 +589,14 @@
mFilters.add(DEFAULT_FILTER);
mBitmap = bitmap;
mSwatches = null;
+
+ // Add the default targets
+ mTargets.add(Target.LIGHT_VIBRANT);
+ mTargets.add(Target.VIBRANT);
+ mTargets.add(Target.DARK_VIBRANT);
+ mTargets.add(Target.LIGHT_MUTED);
+ mTargets.add(Target.MUTED);
+ mTargets.add(Target.DARK_MUTED);
}
/**
@@ -478,15 +613,6 @@
}
/**
- * Set the {@link Generator} to use when generating the {@link Palette}. If this is called
- * with {@code null} then the default generator will be used.
- */
- Builder generator(Generator generator) {
- mGenerator = generator;
- return this;
- }
-
- /**
* Set the maximum number of colors to use in the quantization step when using a
* {@link android.graphics.Bitmap} as the source.
* <p>
@@ -494,6 +620,7 @@
* the range 10-16. For images which are largely made up of people's faces then this
* value should be increased to ~24.
*/
+ @NonNull
public Builder maximumColorCount(int colors) {
mMaxColors = colors;
return this;
@@ -504,13 +631,38 @@
* If the bitmap's largest dimension is greater than the value specified, then the bitmap
* will be resized so that it's largest dimension matches {@code maxDimension}. If the
* bitmap is smaller or equal, the original is used as-is.
+ *
+ * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
+ * abnormal aspect ratios more gracefully.
+ *
+ * @param maxDimension the number of pixels that the max dimension should be scaled down to,
+ * or any value <= 0 to disable resizing.
+ */
+ @NonNull
+ @Deprecated
+ public Builder resizeBitmapSize(final int maxDimension) {
+ mResizeMaxDimension = maxDimension;
+ mResizeArea = -1;
+ return this;
+ }
+
+ /**
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
+ * If the bitmap's area is greater than the value specified, then the bitmap
+ * will be resized so that it's area matches {@code area}. If the
+ * bitmap is smaller or equal, the original is used as-is.
* <p>
* This value has a large effect on the processing time. The larger the resized image is,
* the greater time it will take to generate the palette. The smaller the image is, the
* more detail is lost in the resulting image and thus less precision for color selection.
+ *
+ * @param area the number of pixels that the intemediary scaled down Bitmap should cover,
+ * or any value <= 0 to disable resizing.
*/
- public Builder resizeBitmapSize(int maxDimension) {
- mResizeMaxDimension = maxDimension;
+ @NonNull
+ public Builder resizeBitmapArea(final int area) {
+ mResizeArea = area;
+ mResizeMaxDimension = -1;
return this;
}
@@ -518,6 +670,7 @@
* Clear all added filters. This includes any default filters added automatically by
* {@link Palette}.
*/
+ @NonNull
public Builder clearFilters() {
mFilters.clear();
return this;
@@ -529,6 +682,7 @@
*
* @param filter filter to add.
*/
+ @NonNull
public Builder addFilter(Filter filter) {
if (filter != null) {
mFilters.add(filter);
@@ -545,6 +699,7 @@
* @param right The right side of the rectangle used for the region.
* @param bottom The bottom of the rectangle used for the region.
*/
+ @NonNull
public Builder setRegion(int left, int top, int right, int bottom) {
if (mBitmap != null) {
if (mRegion == null) mRegion = new Rect();
@@ -562,14 +717,41 @@
/**
* Clear any previously region set via {@link #setRegion(int, int, int, int)}.
*/
+ @NonNull
public Builder clearRegion() {
mRegion = null;
return this;
}
/**
+ * Add a target profile to be generated in the palette.
+ *
+ * <p>You can retrieve the result via {@link Palette#getSwatchForTarget(Target)}.</p>
+ */
+ @NonNull
+ public Builder addTarget(@NonNull final Target target) {
+ if (!mTargets.contains(target)) {
+ mTargets.add(target);
+ }
+ return this;
+ }
+
+ /**
+ * Clear all added targets. This includes any default targets added automatically by
+ * {@link Palette}.
+ */
+ @NonNull
+ public Builder clearTargets() {
+ if (mTargets != null) {
+ mTargets.clear();
+ }
+ return this;
+ }
+
+ /**
* Generate and return the {@link Palette} synchronously.
*/
+ @NonNull
public Palette generate() {
final TimingLogger logger = LOG_TIMINGS
? new TimingLogger(LOG_TAG, "Generation")
@@ -578,15 +760,10 @@
List<Swatch> swatches;
if (mBitmap != null) {
- // We have a Bitmap so we need to quantization to reduce the number of colors
+ // We have a Bitmap so we need to use quantization to reduce the number of colors
- if (mResizeMaxDimension <= 0) {
- throw new IllegalArgumentException(
- "Minimum dimension size for resizing should should be >= 1");
- }
-
- // First we'll scale down the bitmap so it's largest dimension is as specified
- final Bitmap bitmap = scaleBitmapDown(mBitmap, mResizeMaxDimension);
+ // First we'll scale down the bitmap if needed
+ final Bitmap bitmap = scaleBitmapDown(mBitmap);
if (logger != null) {
logger.addSplit("Processed Bitmap");
@@ -613,6 +790,7 @@
if (bitmap != mBitmap) {
bitmap.recycle();
}
+
swatches = quantizer.getQuantizedColors();
if (logger != null) {
@@ -623,20 +801,10 @@
swatches = mSwatches;
}
- // If we haven't been provided with a generator, use the default
- if (mGenerator == null) {
- mGenerator = new DefaultGenerator();
- }
-
- // Now call let the Generator do it's thing
- mGenerator.generate(swatches);
-
- if (logger != null) {
- logger.addSplit("Generator.generate() completed");
- }
-
// Now create a Palette instance
- Palette p = new Palette(swatches, mGenerator);
+ final Palette p = new Palette(swatches, mTargets);
+ // And make it generate itself
+ p.generate();
if (logger != null) {
logger.addSplit("Created Palette");
@@ -651,6 +819,7 @@
* {@link PaletteAsyncListener#onGenerated} method will be called with the palette when
* generated.
*/
+ @NonNull
public AsyncTask<Bitmap, Void, Palette> generate(final PaletteAsyncListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener can not be null");
@@ -702,59 +871,34 @@
return subsetPixels;
}
}
- }
-
- static abstract class Generator {
/**
- * This method will be called with the {@link Palette.Swatch} that represent an image.
- * You should process this list so that you have appropriate values when the other methods in
- * class are called.
- * <p>
- * This method will probably be called on a background thread.
+ * Scale the bitmap down as needed.
*/
- public abstract void generate(List<Palette.Swatch> swatches);
+ private Bitmap scaleBitmapDown(final Bitmap bitmap) {
+ double scaleRatio = -1;
- /**
- * Return the most vibrant {@link Palette.Swatch}
- */
- public Palette.Swatch getVibrantSwatch() {
- return null;
- }
+ if (mResizeArea > 0) {
+ final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
+ if (bitmapArea > mResizeArea) {
+ scaleRatio = mResizeArea / (double) bitmapArea;
+ }
+ } else if (mResizeMaxDimension > 0) {
+ final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+ if (maxDimension > mResizeMaxDimension) {
+ scaleRatio = mResizeMaxDimension / (double) maxDimension;
+ }
+ }
- /**
- * Return a light and vibrant {@link Palette.Swatch}
- */
- public Palette.Swatch getLightVibrantSwatch() {
- return null;
- }
+ if (scaleRatio <= 0) {
+ // Scaling has been disabled or not needed so just return the Bitmap
+ return bitmap;
+ }
- /**
- * Return a dark and vibrant {@link Palette.Swatch}
- */
- public Palette.Swatch getDarkVibrantSwatch() {
- return null;
- }
-
- /**
- * Return a muted {@link Palette.Swatch}
- */
- public Palette.Swatch getMutedSwatch() {
- return null;
- }
-
- /**
- * Return a muted and light {@link Palette.Swatch}
- */
- public Palette.Swatch getLightMutedSwatch() {
- return null;
- }
-
- /**
- * Return a muted and dark {@link Palette.Swatch}
- */
- public Palette.Swatch getDarkMutedSwatch() {
- return null;
+ return Bitmap.createScaledBitmap(bitmap,
+ (int) Math.ceil(bitmap.getWidth() * scaleRatio),
+ (int) Math.ceil(bitmap.getHeight() * scaleRatio),
+ false);
}
}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Target.java b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
new file mode 100644
index 0000000..8ac8205
--- /dev/null
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Target.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.graphics;
+
+import android.support.annotation.FloatRange;
+
+/**
+ * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
+ * can be created via the {@link Builder} class.
+ *
+ * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
+ * Palette.</p>
+ */
+public final class Target {
+
+ private static final float TARGET_DARK_LUMA = 0.26f;
+ private static final float MAX_DARK_LUMA = 0.45f;
+
+ private static final float MIN_LIGHT_LUMA = 0.55f;
+ private static final float TARGET_LIGHT_LUMA = 0.74f;
+
+ private static final float MIN_NORMAL_LUMA = 0.3f;
+ private static final float TARGET_NORMAL_LUMA = 0.5f;
+ private static final float MAX_NORMAL_LUMA = 0.7f;
+
+ private static final float TARGET_MUTED_SATURATION = 0.3f;
+ private static final float MAX_MUTED_SATURATION = 0.4f;
+
+ private static final float TARGET_VIBRANT_SATURATION = 1f;
+ private static final float MIN_VIBRANT_SATURATION = 0.35f;
+
+ private static final float WEIGHT_SATURATION = 0.24f;
+ private static final float WEIGHT_LUMA = 0.52f;
+ private static final float WEIGHT_POPULATION = 0.24f;
+
+ private static final int INDEX_MIN = 0;
+ private static final int INDEX_TARGET = 1;
+ private static final int INDEX_MAX = 2;
+
+ private static final int INDEX_WEIGHT_SAT = 0;
+ private static final int INDEX_WEIGHT_LUMA = 1;
+ private static final int INDEX_WEIGHT_POP = 2;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is light in luminance.
+ */
+ public static final Target LIGHT_VIBRANT;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is neither light or dark.
+ */
+ public static final Target VIBRANT;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is dark in luminance.
+ */
+ public static final Target DARK_VIBRANT;
+
+ /**
+ * A target which has the characteristics of a muted color which is light in luminance.
+ */
+ public static final Target LIGHT_MUTED;
+
+ /**
+ * A target which has the characteristics of a muted color which is neither light or dark.
+ */
+ public static final Target MUTED;
+
+ /**
+ * A target which has the characteristics of a muted color which is dark in luminance.
+ */
+ public static final Target DARK_MUTED;
+
+ static {
+ LIGHT_VIBRANT = new Target();
+ setDefaultLightLightnessValues(LIGHT_VIBRANT);
+ setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
+
+ VIBRANT = new Target();
+ setDefaultNormalLightnessValues(VIBRANT);
+ setDefaultVibrantSaturationValues(VIBRANT);
+
+ DARK_VIBRANT = new Target();
+ setDefaultDarkLightnessValues(DARK_VIBRANT);
+ setDefaultVibrantSaturationValues(DARK_VIBRANT);
+
+ LIGHT_MUTED = new Target();
+ setDefaultLightLightnessValues(LIGHT_MUTED);
+ setDefaultMutedSaturationValues(LIGHT_MUTED);
+
+ MUTED = new Target();
+ setDefaultNormalLightnessValues(MUTED);
+ setDefaultMutedSaturationValues(MUTED);
+
+ DARK_MUTED = new Target();
+ setDefaultDarkLightnessValues(DARK_MUTED);
+ setDefaultMutedSaturationValues(DARK_MUTED);
+ }
+
+ private final float[] mSaturationTargets = new float[3];
+ private final float[] mLightnessTargets = new float[3];
+ private final float[] mWeights = new float[3];
+ private boolean mIsExclusive = true; // default to true
+
+ private Target() {
+ setTargetDefaultValues(mSaturationTargets);
+ setTargetDefaultValues(mLightnessTargets);
+ setDefaultWeights();
+ }
+
+ private Target(Target from) {
+ System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
+ mSaturationTargets.length);
+ System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
+ mLightnessTargets.length);
+ System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
+ }
+
+ /**
+ * The minimum saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMinimumSaturation() {
+ return mSaturationTargets[INDEX_MIN];
+ }
+
+ /**
+ * The target saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getTargetSaturation() {
+ return mSaturationTargets[INDEX_TARGET];
+ }
+
+ /**
+ * The maximum saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMaximumSaturation() {
+ return mSaturationTargets[INDEX_MAX];
+ }
+
+ /**
+ * The minimum lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMinimumLightness() {
+ return mLightnessTargets[INDEX_MIN];
+ }
+
+ /**
+ * The target lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getTargetLightness() {
+ return mLightnessTargets[INDEX_TARGET];
+ }
+
+ /**
+ * The maximum lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMaximumLightness() {
+ return mLightnessTargets[INDEX_MAX];
+ }
+
+ /**
+ * The weight of important that a color's saturation value has on selection.
+ */
+ public float getSaturationWeight() {
+ return mWeights[INDEX_WEIGHT_SAT];
+ }
+
+ /**
+ * The weight of important that a color's lightness value has on selection.
+ */
+ public float getLightnessWeight() {
+ return mWeights[INDEX_WEIGHT_LUMA];
+ }
+
+ /**
+ * The weight of important that a color's population value has on selection.
+ */
+ public float getPopulationWeight() {
+ return mWeights[INDEX_WEIGHT_POP];
+ }
+
+ /**
+ * Returns whether any color selected for this target is exclusive for this target only.
+ *
+ * <p>If false, then the color can be selected for other targets.</p>
+ */
+ public boolean isExclusive() {
+ return mIsExclusive;
+ }
+
+ private static void setTargetDefaultValues(final float[] values) {
+ values[INDEX_MIN] = 0f;
+ values[INDEX_TARGET] = 0.5f;
+ values[INDEX_MAX] = 1f;
+ }
+
+ private void setDefaultWeights() {
+ mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
+ mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
+ mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
+ }
+
+ void normalizeWeights() {
+ float sum = 0;
+ for (int i = 0, z = mWeights.length; i < z; i++) {
+ float weight = mWeights[i];
+ if (weight > 0) {
+ sum += weight;
+ }
+ }
+ if (sum != 0) {
+ for (int i = 0, z = mWeights.length; i < z; i++) {
+ if (mWeights[i] > 0) {
+ mWeights[i] /= sum;
+ }
+ }
+ }
+ }
+
+ private static void setDefaultDarkLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
+ target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
+ }
+
+ private static void setDefaultNormalLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
+ target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
+ }
+
+ private static void setDefaultLightLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
+ }
+
+ private static void setDefaultVibrantSaturationValues(Target target) {
+ target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
+ target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
+ }
+
+ private static void setDefaultMutedSaturationValues(Target target) {
+ target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
+ target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
+ }
+
+ /**
+ * Builder class for generating custom {@link Target} instances.
+ */
+ public final static class Builder {
+ private final Target mTarget;
+
+ /**
+ * Create a new {@link Target} builder from scratch.
+ */
+ public Builder() {
+ mTarget = new Target();
+ }
+
+ /**
+ * Create a new builder based on an existing {@link Target}.
+ */
+ public Builder(Target target) {
+ mTarget = new Target(target);
+ }
+
+ /**
+ * Set the minimum saturation value for this target.
+ */
+ public Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_MIN] = value;
+ return this;
+ }
+
+ /**
+ * Set the target/ideal saturation value for this target.
+ */
+ public Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_TARGET] = value;
+ return this;
+ }
+
+ /**
+ * Set the maximum saturation value for this target.
+ */
+ public Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_MAX] = value;
+ return this;
+ }
+
+ /**
+ * Set the minimum lightness value for this target.
+ */
+ public Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_MIN] = value;
+ return this;
+ }
+
+ /**
+ * Set the target/ideal lightness value for this target.
+ */
+ public Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_TARGET] = value;
+ return this;
+ }
+
+ /**
+ * Set the maximum lightness value for this target.
+ */
+ public Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_MAX] = value;
+ return this;
+ }
+
+ /**
+ * Set the weight of important that a color's saturation value has on selection. A weight
+ * of <= 0 means that it has no weight and is ignored.
+ */
+ public Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
+ return this;
+ }
+
+ /**
+ * Set the weight of important that a color's lightness value has on selection. A weight
+ * of <= 0 means that it has no weight and is ignored.
+ */
+ public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
+ return this;
+ }
+
+ /**
+ * Set the weight of important that a color's population value has on selection. A weight
+ * of <= 0 means that it has no weight and is ignored.
+ */
+ public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
+ return this;
+ }
+
+ /**
+ * Set whether any color selected for this target is exclusive to this target only.
+ * Defaults to true.
+ *
+ * @param exclusive true if any the color is exclusive to this target, or false is the
+ * color can be selected for other targets.
+ */
+ public Builder setExclusive(boolean exclusive) {
+ mTarget.mIsExclusive = exclusive;
+ return this;
+ }
+
+ /**
+ * Builds and returns the resulting {@link Target}.
+ */
+ public Target build() {
+ return mTarget;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index 25b686d..c9f1a22 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -78,6 +78,17 @@
artifacts.add('archives', sourcesJarTask);
}
+// TODO make this generic for all projects
+afterEvaluate {
+ def originalTask = tasks['packageDebugAndroidTest']
+ tasks['assembleDebugAndroidTest'].doLast {
+ copy {
+ from(originalTask.outputFile)
+ into(rootProject.ext.testApkDistOut)
+ }
+ }
+}
+
uploadArchives {
repositories {
mavenDeployer {