Merge "Fix subsequent drag-to-open SubMenus" into lmp-mr1-ub-dev
diff --git a/build.gradle b/build.gradle
index 82de0c2..5d8a0cb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@
maven { url '../../prebuilts/tools/common/m2/internal' }
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.2.3'
+ classpath 'com.android.tools.build:gradle:1.3.0-beta2'
}
}
@@ -166,6 +166,7 @@
project.plugins.whenPluginAdded { plugin ->
if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
project.android.buildToolsVersion = rootProject.buildToolsVersion
+ project.android.aaptOptions.useNewCruncher = false
}
}
}
diff --git a/design/api/current.txt b/design/api/current.txt
index 9dc6e20..e630e17 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -229,6 +229,7 @@
method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
method public android.support.design.widget.Snackbar setText(int);
method public void show();
+ field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
field public static final int LENGTH_LONG = 0; // 0x0
field public static final int LENGTH_SHORT = -1; // 0xffffffff
}
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
index 7c09925..71611e6 100644
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
@@ -377,14 +377,22 @@
private void showScrim() {
if (!mScrimsAreShown) {
- animateScrim(255);
+ if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
+ animateScrim(255);
+ } else {
+ setScrimAlpha(255);
+ }
mScrimsAreShown = true;
}
}
private void hideScrim() {
if (mScrimsAreShown) {
- animateScrim(0);
+ if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
+ animateScrim(0);
+ } else {
+ setScrimAlpha(0);
+ }
mScrimsAreShown = false;
}
}
@@ -398,15 +406,7 @@
mScrimAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimatorCompat animator) {
- final int newAlpha = animator.getAnimatedIntValue();
- if (newAlpha != mScrimAlpha) {
- final Drawable contentScrim = mContentScrim;
- if (contentScrim != null && mToolbar != null) {
- ViewCompat.postInvalidateOnAnimation(mToolbar);
- }
- mScrimAlpha = newAlpha;
- ViewCompat.postInvalidateOnAnimation(CollapsingToolbarLayout.this);
- }
+ setScrimAlpha(animator.getAnimatedIntValue());
}
});
} else if (mScrimAnimator.isRunning()) {
@@ -417,6 +417,17 @@
mScrimAnimator.start();
}
+ private void setScrimAlpha(int alpha) {
+ if (alpha != mScrimAlpha) {
+ final Drawable contentScrim = mContentScrim;
+ if (contentScrim != null && mToolbar != null) {
+ ViewCompat.postInvalidateOnAnimation(mToolbar);
+ }
+ mScrimAlpha = alpha;
+ ViewCompat.postInvalidateOnAnimation(CollapsingToolbarLayout.this);
+ }
+ }
+
/**
* Set the drawable to use for the content scrim from resources. Providing null will disable
* the scrim functionality.
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
index 13262a2..42af049 100644
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ b/design/src/android/support/design/widget/FloatingActionButton.java
@@ -247,7 +247,7 @@
if (getVisibility() != VISIBLE) {
return;
}
- if (ViewCompat.isLaidOut(this)) {
+ if (ViewCompat.isLaidOut(this) && !isInEditMode()) {
mImpl.hide();
} else {
setVisibility(GONE);
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
index f3df4f9..83888ce 100644
--- a/design/src/android/support/design/widget/Snackbar.java
+++ b/design/src/android/support/design/widget/Snackbar.java
@@ -95,11 +95,19 @@
/**
* @hide
*/
- @IntDef({LENGTH_SHORT, LENGTH_LONG})
+ @IntDef({LENGTH_INDEFINITE, LENGTH_SHORT, LENGTH_LONG})
@Retention(RetentionPolicy.SOURCE)
public @interface Duration {}
/**
+ * Show the Snackbar indefinitely. This means that the Snackbar will be displayed from the time
+ * that is {@link #show() shown} until either it is dismissed, or another Snackbar is shown.
+ *
+ * @see #setDuration
+ */
+ public static final int LENGTH_INDEFINITE = -2;
+
+ /**
* Show the Snackbar for a short period of time.
*
* @see #setDuration
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
index c6b8f18..c4c54a2 100644
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ b/design/src/android/support/design/widget/SnackbarManager.java
@@ -200,6 +200,11 @@
}
private void scheduleTimeoutLocked(SnackbarRecord r) {
+ if (r.duration == Snackbar.LENGTH_INDEFINITE) {
+ // If we're set to indefinite, we don't want to set a timeout
+ return;
+ }
+
int durationMs = LONG_DURATION_MS;
if (r.duration > 0) {
durationMs = r.duration;
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index 6e0153a..a51170f 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -785,6 +785,10 @@
}
void selectTab(Tab tab) {
+ selectTab(tab, true);
+ }
+
+ void selectTab(Tab tab, boolean updateIndicator) {
if (mSelectedTab == tab) {
if (mSelectedTab != null) {
if (mOnTabSelectedListener != null) {
@@ -795,15 +799,15 @@
} else {
final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
setSelectedTabView(newPosition);
-
- if ((mSelectedTab == null || mSelectedTab.getPosition() == Tab.INVALID_POSITION)
- && newPosition != Tab.INVALID_POSITION) {
- // If we don't currently have a tab, just draw the indicator
- setScrollPosition(newPosition, 0f, true);
- } else {
- animateToTab(newPosition);
+ if (updateIndicator) {
+ if ((mSelectedTab == null || mSelectedTab.getPosition() == Tab.INVALID_POSITION)
+ && newPosition != Tab.INVALID_POSITION) {
+ // If we don't currently have a tab, just draw the indicator
+ setScrollPosition(newPosition, 0f, true);
+ } else {
+ animateToTab(newPosition);
+ }
}
-
if (mSelectedTab != null && mOnTabSelectedListener != null) {
mOnTabSelectedListener.onTabUnselected(mSelectedTab);
}
@@ -1146,14 +1150,13 @@
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mTabMaxWidth != 0 && getMeasuredWidth() > mTabMaxWidth) {
- // Re-measure if we went beyond our maximum size.
- super.onMeasure(MeasureSpec.makeMeasureSpec(
- mTabMaxWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
- } else if (mTabMinWidth > 0 && getMeasuredHeight() < mTabMinWidth) {
- // Re-measure if we're below our minimum size.
- super.onMeasure(MeasureSpec.makeMeasureSpec(
- mTabMinWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
+ final int measuredWidth = getMeasuredWidth();
+ if (measuredWidth < mTabMinWidth || measuredWidth > mTabMaxWidth) {
+ // Re-measure if we are outside our min or max width
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ MathUtils.constrain(measuredWidth, mTabMinWidth, mTabMaxWidth),
+ MeasureSpec.EXACTLY);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@@ -1556,8 +1559,11 @@
@Override
public void onPageSelected(int position) {
final TabLayout tabLayout = mTabLayoutRef.get();
- if (mScrollState == SCROLL_STATE_IDLE && tabLayout != null) {
- tabLayout.getTabAt(position).select();
+ if (tabLayout != null) {
+ // Select the tab, only updating the indicator if we're not being dragged/settled
+ // (since onPageScrolled will handle that).
+ tabLayout.selectTab(tabLayout.getTabAt(position),
+ mScrollState == SCROLL_STATE_IDLE);
}
}
}
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 884e538..15173cc 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -17,7 +17,6 @@
package android.support.design.widget;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -81,7 +80,8 @@
private TextView mErrorView;
private int mErrorTextAppearance;
- private ColorStateList mLabelTextColor;
+ private int mDefaultTextColor;
+ private int mFocusedTextColor;
private final CollapsingTextHelper mCollapsingTextHelper;
private final Handler mHandler;
@@ -127,14 +127,12 @@
mErrorTextAppearance = a.getResourceId(R.styleable.TextInputLayout_errorTextAppearance, 0);
final boolean errorEnabled = a.getBoolean(R.styleable.TextInputLayout_errorEnabled, false);
+
+ mDefaultTextColor = getThemeAttrColor(android.R.attr.textColorHint);
+ mFocusedTextColor = mCollapsingTextHelper.getCollapsedTextColor();
- // We create a ColorStateList using the specified text color, combining it with our
- // theme's textColorHint
- mLabelTextColor = createLabelTextColorStateList(
- mCollapsingTextHelper.getCollapsedTextColor());
-
- mCollapsingTextHelper.setCollapsedTextColor(mLabelTextColor.getDefaultColor());
- mCollapsingTextHelper.setExpandedTextColor(mLabelTextColor.getDefaultColor());
+ mCollapsingTextHelper.setCollapsedTextColor(mDefaultTextColor);
+ mCollapsingTextHelper.setExpandedTextColor(mDefaultTextColor);
a.recycle();
@@ -199,6 +197,9 @@
}
});
+ // Use the EditText's hint colors since the developer may have changed it
+ mDefaultTextColor = mEditText.getHintTextColors().getDefaultColor();
+
// Add focus listener to the EditText so that we can notify the label that it is activated.
// Allows the use of a ColorStateList for the text color on the label
mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
@@ -239,9 +240,9 @@
boolean hasText = !TextUtils.isEmpty(mEditText.getText());
boolean isFocused = mEditText.isFocused();
- mCollapsingTextHelper.setCollapsedTextColor(mLabelTextColor.getColorForState(
- isFocused ? FOCUSED_STATE_SET : EMPTY_STATE_SET,
- mLabelTextColor.getDefaultColor()));
+ mCollapsingTextHelper.setExpandedTextColor(mDefaultTextColor);
+ mCollapsingTextHelper.setCollapsedTextColor(
+ isFocused ? mFocusedTextColor : mDefaultTextColor);
if (hasText || isFocused) {
// We should be showing the label so do so if it isn't already
@@ -404,23 +405,6 @@
mAnimator.start();
}
- private ColorStateList createLabelTextColorStateList(int color) {
- final int[][] states = new int[2][];
- final int[] colors = new int[2];
- int i = 0;
-
- // Focused
- states[i] = FOCUSED_STATE_SET;
- colors[i] = color;
- i++;
-
- states[i] = EMPTY_STATE_SET;
- colors[i] = getThemeAttrColor(android.R.attr.textColorHint);
- i++;
-
- return new ColorStateList(states, colors);
- }
-
private int getThemeAttrColor(int attr) {
TypedValue tv = new TypedValue();
if (getContext().getTheme().resolveAttribute(attr, tv, true)) {
diff --git a/v7/appcompat/res/values-v21/styles_base.xml b/v7/appcompat/res/values-v21/styles_base.xml
index 1bf90ef..241cb04 100644
--- a/v7/appcompat/res/values-v21/styles_base.xml
+++ b/v7/appcompat/res/values-v21/styles_base.xml
@@ -174,6 +174,8 @@
<style name="Base.Widget.AppCompat.AutoCompleteTextView" parent="android:Widget.Material.AutoCompleteTextView" />
+ <style name="Base.Widget.AppCompat.EditText" parent="android:Widget.Material.EditText" />
+
<style name="Base.Widget.AppCompat.RatingBar" parent="android:Widget.Material.RatingBar" />
<style name="Base.Widget.AppCompat.Button" parent="android:Widget.Material.Button" />
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index b38c6ad..0ac20d5 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -194,9 +194,7 @@
<style name="Widget.AppCompat.SearchView" parent="Base.Widget.AppCompat.SearchView" />
<style name="Widget.AppCompat.SearchView.ActionBar" parent="Base.Widget.AppCompat.SearchView.ActionBar" />
- <style name="Widget.AppCompat.EditText"
- parent="Base.Widget.AppCompat.EditText">
- </style>
+ <style name="Widget.AppCompat.EditText" parent="Base.Widget.AppCompat.EditText"/>
<style name="Widget.AppCompat.CompoundButton.Switch" parent="Base.Widget.AppCompat.CompoundButton.Switch" />
diff --git a/v7/palette/api/current.txt b/v7/palette/api/current.txt
index d92c0dd..1b6c745 100644
--- a/v7/palette/api/current.txt
+++ b/v7/palette/api/current.txt
@@ -25,12 +25,18 @@
public static final class Palette.Builder {
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 clearFilters();
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);
}
+ public static abstract interface Palette.Filter {
+ method public abstract boolean isAllowed(int, float[]);
+ }
+
public static abstract interface Palette.PaletteAsyncListener {
method public abstract void onGenerated(android.support.v7.graphics.Palette);
}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
index 9355502..3b89748 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
@@ -16,7 +16,6 @@
package android.support.v7.graphics;
-import android.graphics.Bitmap;
import android.graphics.Color;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.graphics.Palette.Swatch;
@@ -47,9 +46,6 @@
private static final String LOG_TAG = "ColorCutQuantizer";
private static final boolean LOG_TIMINGS = false;
- private static final float BLACK_MAX_LIGHTNESS = 0.05f;
- private static final float WHITE_MIN_LIGHTNESS = 0.95f;
-
private static final int COMPONENT_RED = -3;
private static final int COMPONENT_GREEN = -2;
private static final int COMPONENT_BLUE = -1;
@@ -61,33 +57,20 @@
final int[] mHistogram;
final List<Swatch> mQuantizedColors;
final TimingLogger mTimingLogger;
+ final Palette.Filter[] mFilters;
private final float[] mTempHsl = new float[3];
/**
- * Factory-method to generate a {@link ColorCutQuantizer} from a {@link Bitmap} object.
- *
- * @param bitmap Bitmap to extract the pixel data from
- * @param maxColors The maximum number of colors that should be in the result palette.
- */
- static ColorCutQuantizer fromBitmap(Bitmap bitmap, int maxColors) {
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
-
- final int[] pixels = new int[width * height];
- bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
-
- return new ColorCutQuantizer(pixels, maxColors);
- }
-
- /**
- * Private constructor.
+ * Constructor.
*
* @param pixels histogram representing an image's pixel data
* @param maxColors The maximum number of colors that should be in the result palette.
+ * @param filters Set of filters to use in the quantization stage
*/
- private ColorCutQuantizer(final int[] pixels, final int maxColors) {
+ ColorCutQuantizer(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
+ mFilters = filters;
final int[] hist = mHistogram = new int[1 << (QUANTIZE_WORD_WIDTH * 3)];
for (int i = 0; i < pixels.length; i++) {
@@ -443,37 +426,24 @@
}
private boolean shouldIgnoreColor(int color565) {
- ColorUtils.colorToHSL(approximateToRgb888(color565), mTempHsl);
- return shouldIgnoreColor(mTempHsl);
+ final int rgb = approximateToRgb888(color565);
+ ColorUtils.colorToHSL(rgb, mTempHsl);
+ return shouldIgnoreColor(rgb, mTempHsl);
}
- private static boolean shouldIgnoreColor(Swatch color) {
- return shouldIgnoreColor(color.getHsl());
+ private boolean shouldIgnoreColor(Swatch color) {
+ return shouldIgnoreColor(color.getRgb(), color.getHsl());
}
- private static boolean shouldIgnoreColor(float[] hslColor) {
- return isWhite(hslColor) || isBlack(hslColor) || isNearRedILine(hslColor);
- }
-
- /**
- * @return true if the color represents a color which is close to black.
- */
- private static boolean isBlack(float[] hslColor) {
- return hslColor[2] <= BLACK_MAX_LIGHTNESS;
- }
-
- /**
- * @return true if the color represents a color which is close to white.
- */
- private static boolean isWhite(float[] hslColor) {
- return hslColor[2] >= WHITE_MIN_LIGHTNESS;
- }
-
- /**
- * @return true if the color lies close to the red side of the I line.
- */
- private static boolean isNearRedILine(float[] hslColor) {
- return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ private boolean shouldIgnoreColor(int rgb, float[] hsl) {
+ if (mFilters != null && mFilters.length > 0) {
+ for (int i = 0, count = mFilters.length; i < count; i++) {
+ if (!mFilters[i].isAllowed(rgb, hsl)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/**
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 7a4e7ee..c3f3e78 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
@@ -23,6 +23,7 @@
import android.support.v4.os.AsyncTaskCompat;
import android.util.TimingLogger;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -427,6 +428,7 @@
private Bitmap mBitmap;
private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
private int mResizeMaxDimension = DEFAULT_RESIZE_BITMAP_MAX_DIMENSION;
+ private final List<Filter> mFilters = new ArrayList<>();
private Generator mGenerator;
@@ -434,6 +436,7 @@
* Construct a new {@link Builder} using a source {@link Bitmap}
*/
public Builder(Bitmap bitmap) {
+ this();
if (bitmap == null || bitmap.isRecycled()) {
throw new IllegalArgumentException("Bitmap is not valid");
}
@@ -445,12 +448,17 @@
* Typically only used for testing.
*/
public Builder(List<Swatch> swatches) {
+ this();
if (swatches == null || swatches.isEmpty()) {
throw new IllegalArgumentException("List of Swatches is not valid");
}
mSwatches = swatches;
}
+ private Builder() {
+ mFilters.add(DEFAULT_FILTER);
+ }
+
/**
* 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.
@@ -489,6 +497,28 @@
}
/**
+ * Clear all added filters. This includes any default filters added automatically by
+ * {@link Palette}.
+ */
+ public Builder clearFilters() {
+ mFilters.clear();
+ return this;
+ }
+
+ /**
+ * Add a filter to be able to have fine grained controlled over the colors which are
+ * allowed in the resulting palette.
+ *
+ * @param filter filter to add.
+ */
+ public Builder addFilter(Filter filter) {
+ if (filter != null) {
+ mFilters.add(filter);
+ }
+ return this;
+ }
+
+ /**
* Generate and return the {@link Palette} synchronously.
*/
public Palette generate() {
@@ -514,8 +544,13 @@
}
// Now generate a quantizer from the Bitmap
- ColorCutQuantizer quantizer = ColorCutQuantizer
- .fromBitmap(scaledBitmap, mMaxColors);
+ final int width = scaledBitmap.getWidth();
+ final int height = scaledBitmap.getHeight();
+ final int[] pixels = new int[width * height];
+ scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+
+ final ColorCutQuantizer quantizer = new ColorCutQuantizer(pixels, mMaxColors,
+ mFilters.isEmpty() ? null : mFilters.toArray(new Filter[mFilters.size()]));
// If created a new bitmap, recycle it
if (scaledBitmap != mBitmap) {
@@ -633,4 +668,55 @@
}
}
+ /**
+ * A Filter provides a mechanism for exercising fine-grained control over which colors
+ * are valid within a resulting {@link Palette}.
+ */
+ public interface Filter {
+ /**
+ * Hook to allow clients to be able filter colors from resulting palette.
+ *
+ * @param rgb the color in RGB888.
+ * @param hsl HSL representation of the color.
+ *
+ * @return true if the color is allowed, false if not.
+ *
+ * @see Builder#addFilter(Filter)
+ */
+ boolean isAllowed(int rgb, float[] hsl);
+ }
+
+ /**
+ * The default filter.
+ */
+ private static final Filter DEFAULT_FILTER = new Filter() {
+ private static final float BLACK_MAX_LIGHTNESS = 0.05f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.95f;
+
+ @Override
+ public boolean isAllowed(int rgb, float[] hsl) {
+ return !isWhite(hsl) && !isBlack(hsl) && !isNearRedILine(hsl);
+ }
+
+ /**
+ * @return true if the color represents a color which is close to black.
+ */
+ private boolean isBlack(float[] hslColor) {
+ return hslColor[2] <= BLACK_MAX_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color represents a color which is close to white.
+ */
+ private boolean isWhite(float[] hslColor) {
+ return hslColor[2] >= WHITE_MIN_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color lies close to the red side of the I line.
+ */
+ private boolean isNearRedILine(float[] hslColor) {
+ return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ }
+ };
}