Added min support to ProgressBar and SeekBar

ProgressBar, AbsSeekBar, and SeekBar now support min attributes for the
lower range of the progress bar. It used to be 0 by default.

Change-Id: I3308eff80f4c7f58a940dec9cc517dcdff4a1d83
diff --git a/api/current.txt b/api/current.txt
index 7b8930c..6e5666c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -855,6 +855,7 @@
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
+    field public static final int min = 16843367; // 0x1010267
     field public static final int minDate = 16843583; // 0x101033f
     field public static final int minEms = 16843098; // 0x101015a
     field public static final int minHeight = 16843072; // 0x1010140
@@ -47475,6 +47476,7 @@
     method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method public synchronized int getMax();
+    method public synchronized int getMin();
     method public synchronized int getProgress();
     method public android.content.res.ColorStateList getProgressBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -47497,6 +47499,7 @@
     method public void setInterpolator(android.content.Context, int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public synchronized void setMax(int);
+    method public synchronized void setMin(int);
     method public synchronized void setProgress(int);
     method public void setProgress(int, boolean);
     method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
diff --git a/api/system-current.txt b/api/system-current.txt
index ca1c61d..7044e77 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -962,6 +962,7 @@
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
+    field public static final int min = 16843367; // 0x1010267
     field public static final int minDate = 16843583; // 0x101033f
     field public static final int minEms = 16843098; // 0x101015a
     field public static final int minHeight = 16843072; // 0x1010140
@@ -51012,6 +51013,7 @@
     method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method public synchronized int getMax();
+    method public synchronized int getMin();
     method public synchronized int getProgress();
     method public android.content.res.ColorStateList getProgressBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -51034,6 +51036,7 @@
     method public void setInterpolator(android.content.Context, int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public synchronized void setMax(int);
+    method public synchronized void setMin(int);
     method public synchronized void setProgress(int);
     method public void setProgress(int, boolean);
     method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
diff --git a/api/test-current.txt b/api/test-current.txt
index eda4019..0ad3466e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -855,6 +855,7 @@
     field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
+    field public static final int min = 16843367; // 0x1010267
     field public static final int minDate = 16843583; // 0x101033f
     field public static final int minEms = 16843098; // 0x101015a
     field public static final int minHeight = 16843072; // 0x1010140
@@ -47563,6 +47564,7 @@
     method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method public synchronized int getMax();
+    method public synchronized int getMin();
     method public synchronized int getProgress();
     method public android.content.res.ColorStateList getProgressBackgroundTintList();
     method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -47585,6 +47587,7 @@
     method public void setInterpolator(android.content.Context, int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public synchronized void setMax(int);
+    method public synchronized void setMin(int);
     method public synchronized void setProgress(int);
     method public void setProgress(int, boolean);
     method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 01a95a4..8ee4334 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -469,7 +469,7 @@
     /**
      * Returns the amount of progress changed via the arrow keys.
      * <p>
-     * By default, this will be a value that is derived from the max progress.
+     * By default, this will be a value that is derived from the progress range.
      *
      * @return The amount to increment or decrement when the user presses the
      *         arrow keys. This will be positive.
@@ -479,13 +479,27 @@
     }
 
     @Override
-    public synchronized void setMax(int max) {
-        super.setMax(max);
+    public synchronized void setMin(int min) {
+        super.setMin(min);
+        int range = getMax() - getMin();
 
-        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
+        if ((mKeyProgressIncrement == 0) || (range / mKeyProgressIncrement > 20)) {
+
             // It will take the user too long to change this via keys, change it
             // to something more reasonable
-            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
+            setKeyProgressIncrement(Math.max(1, Math.round((float) range / 20)));
+        }
+    }
+
+    @Override
+    public synchronized void setMax(int max) {
+        super.setMax(max);
+        int range = getMax() - getMin();
+
+        if ((mKeyProgressIncrement == 0) || (range / mKeyProgressIncrement > 20)) {
+            // It will take the user too long to change this via keys, change it
+            // to something more reasonable
+            setKeyProgressIncrement(Math.max(1, Math.round((float) range / 20)));
         }
     }
 
@@ -596,8 +610,10 @@
     }
 
     private float getScale() {
-        final int max = getMax();
-        return max > 0 ? getProgress() / (float) max : 0;
+        int min = getMin();
+        int max = getMax();
+        int range = max - min;
+        return range > 0 ? (getProgress() - min) / (float) range : 0;
     }
 
     /**
@@ -691,7 +707,7 @@
      */
     void drawTickMarks(Canvas canvas) {
         if (mTickMark != null) {
-            final int count = getMax();
+            final int count = getMax() - getMin();
             if (count > 1) {
                 final int w = mTickMark.getIntrinsicWidth();
                 final int h = mTickMark.getIntrinsicHeight();
@@ -847,8 +863,8 @@
             }
         }
 
-        final int max = getMax();
-        progress += scale * max;
+        final int range = getMax() - getMin();
+        progress += scale * range;
 
         setHotspot(x, y);
         setProgressInternal(Math.round(progress), true, false);
@@ -922,7 +938,7 @@
 
         if (isEnabled()) {
             final int progress = getProgress();
-            if (progress > 0) {
+            if (progress > getMin()) {
                 info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
             }
             if (progress < getMax()) {
@@ -960,7 +976,8 @@
                 if (!canUserSetProgress()) {
                     return false;
                 }
-                int increment = Math.max(1, Math.round((float) getMax() / 20));
+                int range = getMax() - getMin();
+                int increment = Math.max(1, Math.round((float) range / 20));
                 if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
                     increment = -increment;
                 }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 3c967ac..4a28cc4 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -185,6 +185,7 @@
  * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
  * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
  * @attr ref android.R.styleable#ProgressBar_interpolator
+ * @attr ref android.R.styleable#ProgressBar_min
  * @attr ref android.R.styleable#ProgressBar_max
  * @attr ref android.R.styleable#ProgressBar_maxHeight
  * @attr ref android.R.styleable#ProgressBar_maxWidth
@@ -215,7 +216,10 @@
 
     private int mProgress;
     private int mSecondaryProgress;
+    private int mMin;
+    private boolean mMinInitialized;
     private int mMax;
+    private boolean mMaxInitialized;
 
     private int mBehavior;
     private int mDuration;
@@ -308,6 +312,7 @@
             setInterpolator(context, resID);
         }
 
+        setMin(a.getInt(R.styleable.ProgressBar_min, mMin));
         setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
 
         setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
@@ -565,6 +570,7 @@
      * </ul>
      */
     private void initProgressBar() {
+        mMin = 0;
         mMax = 100;
         mProgress = 0;
         mSecondaryProgress = 0;
@@ -1310,7 +1316,8 @@
 
     private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
             boolean callBackToApp, boolean animate) {
-        final float scale = mMax > 0 ? progress / (float) mMax : 0;
+        int range = mMax - mMin;
+        final float scale = range > 0 ? (progress - mMin) / (float) range : 0;
         final boolean isPrimary = id == R.id.progress;
 
         if (isPrimary && animate) {
@@ -1436,7 +1443,7 @@
             return false;
         }
 
-        progress = MathUtils.constrain(progress, 0, mMax);
+        progress = MathUtils.constrain(progress, mMin, mMax);
 
         if (progress == mProgress) {
             // No change from current.
@@ -1466,8 +1473,8 @@
             return;
         }
 
-        if (secondaryProgress < 0) {
-            secondaryProgress = 0;
+        if (secondaryProgress < mMin) {
+            secondaryProgress = mMin;
         }
 
         if (secondaryProgress > mMax) {
@@ -1515,6 +1522,20 @@
     }
 
     /**
+     * <p>Return the lower limit of this progress bar's range.</p>
+     *
+     * @return a positive integer
+     *
+     * @see #setMin(int)
+     * @see #getProgress()
+     * @see #getSecondaryProgress()
+     */
+    @ViewDebug.ExportedProperty(category = "progress")
+    public synchronized int getMin() {
+        return mMin;
+    }
+
+    /**
      * <p>Return the upper limit of this progress bar's range.</p>
      *
      * @return a positive integer
@@ -1529,7 +1550,37 @@
     }
 
     /**
-     * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
+     * <p>Set the lower range of the progress bar to <tt>min</tt>.</p>
+     *
+     * @param min the lower range of this progress bar
+     *
+     * @see #getMin()
+     * @see #setProgress(int)
+     * @see #setSecondaryProgress(int)
+     */
+    @android.view.RemotableViewMethod
+    public synchronized void setMin(int min) {
+        if (mMaxInitialized) {
+            if (min > mMax) {
+                min = mMax;
+            }
+        }
+        mMinInitialized = true;
+        if (mMaxInitialized && min != mMin) {
+            mMin = min;
+            postInvalidate();
+
+            if (mProgress < min) {
+                mProgress = min;
+            }
+            refreshProgress(R.id.progress, mProgress, false, false);
+        } else {
+            mMin = min;
+        }
+    }
+
+    /**
+     * <p>Set the upper range of the progress bar <tt>max</tt>.</p>
      *
      * @param max the upper range of this progress bar
      *
@@ -1539,10 +1590,13 @@
      */
     @android.view.RemotableViewMethod
     public synchronized void setMax(int max) {
-        if (max < 0) {
-            max = 0;
+        if (mMinInitialized) {
+            if (max < mMin) {
+                max = mMin;
+            }
         }
-        if (max != mMax) {
+        mMaxInitialized = true;
+        if (mMinInitialized && max != mMax) {
             mMax = max;
             postInvalidate();
 
@@ -1550,6 +1604,8 @@
                 mProgress = max;
             }
             refreshProgress(R.id.progress, mProgress, false, false);
+        } else {
+            mMax = max;
         }
     }
 
@@ -1959,7 +2015,7 @@
     @Override
     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         super.onInitializeAccessibilityEventInternal(event);
-        event.setItemCount(mMax);
+        event.setItemCount(mMax - mMin);
         event.setCurrentItemIndex(mProgress);
     }
 
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index 5d01d8d..f9aced0 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -46,8 +46,10 @@
          * to distinguish user-initiated changes from those that occurred programmatically.
          *
          * @param seekBar The SeekBar whose progress has changed
-         * @param progress The current progress level. This will be in the range 0..max where max
-         *        was set by {@link ProgressBar#setMax(int)}. (The default value for max is 100.)
+         * @param progress The current progress level. This will be in the range min..max where min
+         *                 and max were set by {@link ProgressBar#setMin(int)} and
+         *                 {@link ProgressBar#setMax(int)}, respectively. (The default values for
+         *                 min is 0 and max is 100.)
          * @param fromUser True if the progress change was initiated by the user.
          */
         void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser);
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index aca2bcc..f0a95bd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3965,6 +3965,7 @@
     </declare-styleable>
 
     <declare-styleable name="ProgressBar">
+        <attr name="min" format="integer" />
         <!-- Defines the maximum value the progress can take. -->
         <attr name="max" format="integer" />
         <!-- Defines the default progress value, between 0 and max. -->
@@ -7931,6 +7932,14 @@
 
     <declare-styleable name="SeekBarPreference">
         <attr name="layout" />
+        <!-- Attribute indicating whether the slider within this preference can be adjusted, that is
+        pressing left/right keys when this preference is focused will move the slider accordingly (e.g.
+        inline adjustable preferences). False, if the slider within the preference is read-only and
+        cannot be adjusted. By default, the seekbar is adjustable. -->
+        <attr name="adjustable" format="boolean" />
+        <!-- Flag indicating whether the TextView next to the seekbar that shows the current seekbar value will be
+        displayed. If true, the view is VISIBLE; if false, the view will be GONE. By default, this view is VISIBLE. -->
+        <attr name="showSeekBarValue" format="boolean" />
     </declare-styleable>
 
     <!-- Base attributes available to PreferenceFragment. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7bce379..7999e7e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2764,4 +2764,5 @@
     <public-group type="id" first-id="0x01020041">
     </public-group>
 
+    <public type="attr" name="min" />
 </resources>