Merge "Create a better placeholder for YT videos when flash is not installed."
diff --git a/api/current.xml b/api/current.xml
index d8c7308..a30426a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26765,6 +26765,21 @@
 <parameter name="day" type="int">
 </parameter>
 </method>
+<method name="setRange"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startYear" type="int">
+</parameter>
+<parameter name="endYear" type="int">
+</parameter>
+</method>
 <method name="updateDate"
  return="void"
  abstract="false"
@@ -235118,6 +235133,21 @@
 <parameter name="onDateChangedListener" type="android.widget.DatePicker.OnDateChangedListener">
 </parameter>
 </method>
+<method name="setRange"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startYear" type="int">
+</parameter>
+<parameter name="endYear" type="int">
+</parameter>
+</method>
 <method name="updateDate"
  return="void"
  abstract="false"
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 448b3ef..e6e55ee 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
-import android.os.Build;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -118,6 +117,28 @@
         mDatePicker.init(year, month, day, null);
     }
 
+    /**
+     * Sets the range of years in which dates can be selected.
+     * <p>
+     * Note: If the range is set to a value that does not include the currently
+     * selected date the value of the picker shown by this dialog will be
+     * updated to the closest date in the range.
+     * </p>
+     *
+     * @param startYear The start year of the range.
+     * @param endYear The end year of the range.
+     */
+    public void setRange(int startYear, int endYear) {
+        mDatePicker.setRange(startYear, endYear);
+    }
+
+    /**
+     * Sets the current date.
+     *
+     * @param year The date year.
+     * @param monthOfYear The date month.
+     * @param dayOfMonth The date day of month.
+     */
     public void updateDate(int year, int monthOfYear, int dayOfMonth) {
         mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 55d3b16..a4ad97b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5830,6 +5830,7 @@
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate();
             }
+            mBackgroundSizeChanged = true;
         }
     }
 
@@ -5882,6 +5883,7 @@
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate();
             }
+            mBackgroundSizeChanged = true;
         }
     }
 
@@ -5937,7 +5939,7 @@
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate();
             }
-
+            mBackgroundSizeChanged = true;
         }
     }
 
@@ -5990,6 +5992,7 @@
                 mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
                 invalidate();
             }
+            mBackgroundSizeChanged = true;
         }
     }
 
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index e98c0bd..668490d 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -104,6 +104,14 @@
             }
         };
 
+        // mini-month day-picker
+        mMiniMonthDayPicker = (DayPicker) findViewById(R.id.mini_month_day_picker);
+        mMiniMonthDayPicker.setOnDateChangeListener(new DayPicker.OnSelectedDayChangeListener() {
+            public void onSelectedDayChange(DayPicker view, int year, int month, int monthDay) {
+                updateDateUnchecked(year, month, monthDay);
+            }
+        });
+
         // day
         mDayPicker = (NumberPicker) findViewById(R.id.day);
         mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
@@ -121,24 +129,11 @@
         mYearPicker.setOnLongPressUpdateInterval(100);
         mYearPicker.setOnChangeListener(onChangeListener);
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
-        int mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
-        int mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
-        mYearPicker.setRange(mStartYear, mEndYear);
+        int startYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
+        int endYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
+        setRange(startYear, endYear);
         a.recycle();
 
-        // mini-month day-picker
-        mMiniMonthDayPicker = (DayPicker) findViewById(R.id.mini_month_day_picker);
-        mTempCalendar.clear();
-        mTempCalendar.set(mStartYear, 0, 1);
-        Calendar endRangeDate = (Calendar) mTempCalendar.clone();
-        endRangeDate.set(mEndYear, 11, 31);
-        mMiniMonthDayPicker.setRange(mTempCalendar, endRangeDate);
-        mMiniMonthDayPicker.setOnDateChangeListener(new DayPicker.OnSelectedDayChangeListener() {
-            public void onSelectedDayChange(DayPicker view, int year, int month, int monthDay) {
-                updateDateUnchecked(year, month, monthDay);
-            }
-        });
-        
         // initialize to current date
         mTempCalendar.setTimeInMillis(System.currentTimeMillis());
         init(mTempCalendar.get(Calendar.YEAR), mTempCalendar.get(Calendar.MONTH),
@@ -148,6 +143,40 @@
         reorderPickers();
     }
 
+    /**
+     * Sets the range of years in which dates can be selected.
+     * <p>
+     * Note: If the range is set to a value that does not include the currently
+     * selected date the value of this picker will be updated to the closest
+     * date in the range.
+     * </p>
+     *
+     * @param startYear The start year of the range.
+     * @param endYear The end year of the range.
+     */
+    public void setRange(int startYear, int endYear) {
+        // set ranges of the widgets
+        mYearPicker.setRange(startYear, endYear);
+        mTempCalendar.clear();
+        Calendar startRangeDate = (Calendar) mTempCalendar.clone();
+        startRangeDate.set(startYear, 0, 1);
+        Calendar endRangeDate = (Calendar) mTempCalendar.clone();
+        endRangeDate.set(endYear, 11, 31);
+        mMiniMonthDayPicker.setRange(startRangeDate, endRangeDate);
+
+        // update state if current date is outside of the range
+        mTempCalendar.set(Calendar.YEAR, getYear());
+        mTempCalendar.set(Calendar.MONTH, getMonth());
+        mTempCalendar.set(Calendar.DAY_OF_MONTH, getDayOfMonth());
+        if (mTempCalendar.before(startRangeDate)) {
+            updateDate(startRangeDate.get(Calendar.YEAR), startRangeDate.get(Calendar.MONTH),
+                    startRangeDate.get(Calendar.DAY_OF_MONTH));
+        } else if (mTempCalendar.after(endRangeDate)) {
+            updateDate(endRangeDate.get(Calendar.YEAR), endRangeDate.get(Calendar.MONTH),
+                    endRangeDate.get(Calendar.DAY_OF_MONTH));
+        }
+    }
+
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
diff --git a/core/java/android/widget/DayPicker.java b/core/java/android/widget/DayPicker.java
index cdf51f7..02805be 100644
--- a/core/java/android/widget/DayPicker.java
+++ b/core/java/android/widget/DayPicker.java
@@ -366,22 +366,38 @@
      * @param endRangeDate The end date.
      */
     public void setRange(Calendar startRangeDate, Calendar endRangeDate) {
-        boolean doSetupAdapter = false;
+        boolean rangeChanged = false;
         if (mRangeStartDate.get(Calendar.DAY_OF_YEAR) != startRangeDate.get(Calendar.DAY_OF_YEAR)
                 || mRangeStartDate.get(Calendar.YEAR) != startRangeDate.get(Calendar.YEAR)) {
             mRangeStartDate.setTimeInMillis(startRangeDate.getTimeInMillis());
             mRangeStartDate.setTimeZone(startRangeDate.getTimeZone());
-            doSetupAdapter = true;
+            rangeChanged = true;
         }
         if (mRangeEndDate.get(Calendar.DAY_OF_YEAR) != endRangeDate.get(Calendar.DAY_OF_YEAR)
                 || mRangeEndDate.get(Calendar.YEAR) != endRangeDate.get(Calendar.YEAR)) {
             mRangeEndDate.setTimeInMillis(endRangeDate.getTimeInMillis());
             mRangeEndDate.setTimeZone(endRangeDate.getTimeZone());
-            doSetupAdapter = true;
-            
+            rangeChanged = true;
         }
-        if (doSetupAdapter) {
-            setUpAdapter();
+
+        if (!rangeChanged) {
+            return;
+        }
+
+        // now recreate the adapter since we have a new range to handle
+        mAdapter = null;
+        setUpAdapter();
+
+        // set the current date to today if in the range
+        // otherwise to the closest end of the range
+        mTempCalendar.clear();
+        mTempCalendar.setTimeInMillis(System.currentTimeMillis());
+        if (mTempCalendar.before(mRangeStartDate)) {
+            goTo(mRangeStartDate, false, true, true);
+        } else if (mTempCalendar.after(mRangeEndDate)) {
+            goTo(mRangeEndDate, false, true, true);
+        } else {
+            goTo(mTempCalendar, false, true, true);
         }
     }
 
@@ -629,7 +645,6 @@
         }
 
         // Figure out where we are
-        int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0;
         long currScroll = view.getFirstVisiblePosition() * child.getHeight() - child.getBottom();
 
         // If we have moved since our last call update the direction
@@ -645,6 +660,7 @@
         // causes the month to transition when two full weeks of a month are
         // visible when scrolling up, and when the first day in a month reaches
         // the top of the screen when scrolling down.
+        int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0;
         if (mIsScrollingUp) {
             child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset);
         } else if (offset != 0) {
@@ -712,8 +728,9 @@
             throw new IllegalArgumentException("fromDate: " + mRangeStartDate.getTime()
                     + " does not precede toDate: " + toDate.getTime());
         }
+
         int fromDateDayOfWeek = mRangeStartDate.get(Calendar.DAY_OF_WEEK);
-        long diff = (fromDateDayOfWeek - toDate.getFirstDayOfWeek()) * MILLIS_IN_DAY;
+        long diff = (fromDateDayOfWeek - mFirstDayOfWeek) * MILLIS_IN_DAY;
         if (diff < 0) {
             diff = diff + MILLIS_IN_WEEK;
         }
@@ -874,7 +891,16 @@
         protected void init() {
             mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
             mSelectedWeek = getWeeksDelta(mSelectedDay);
-            mTotalWeekCount = getWeeksDelta(mRangeEndDate);
+
+            // make adjustment to fit the range last week with needed overflow
+            mTempCalendar.setTimeInMillis(mRangeEndDate.getTimeInMillis());
+            mTempCalendar.setTimeZone(mRangeEndDate.getTimeZone());
+            int diff = mFirstDayOfWeek - mRangeEndDate.get(Calendar.DAY_OF_WEEK);
+            if (diff < 0) {
+                diff += DAYS_PER_WEEK;
+            }
+            mTempCalendar.add(Calendar.DAY_OF_WEEK, diff);
+            mTotalWeekCount = getWeeksDelta(mTempCalendar);
         }
 
         /**
@@ -892,7 +918,6 @@
             mSelectedWeek = getWeeksDelta(mSelectedDay);
             mFocusMonth = mSelectedDay.get(Calendar.MONTH);
             notifyDataSetChanged();
-            invalidate();  // Test
         }
 
         /**
@@ -1004,9 +1029,12 @@
             if (mGestureDetector.onTouchEvent(event)) {
                 WeekView weekView = (WeekView) v;
                 weekView.getDayFromLocation(event.getX(), mTempCalendar);
-                if (mTempCalendar.get(Calendar.YEAR) != 0) {
-                    onDayTapped(mTempCalendar);
+                // it is possible that the touched day is outside the valid range
+                // we draw whole weeks but range end can fall not on the week end
+                if (mTempCalendar.before(mRangeStartDate) || mTempCalendar.after(mRangeEndDate)) {
+                    return true;
                 }
+                onDayTapped(mTempCalendar);
                 return true;
             }
             return false;
@@ -1019,6 +1047,7 @@
          */
         protected void onDayTapped(Calendar day) {
             setSelectedDay(day);
+            setMonthDisplayed(day);
         }
 
         /**
@@ -1244,8 +1273,8 @@
                 mNumCells = mShowWeekNumber ? mWeekDayCount + 1 : mWeekDayCount;
             }
             mWeek = ((int[]) params.get(VIEW_PARAMS_WEEK))[0];
-            mTempCalendar.clear();
-            mTempCalendar.set(1900, 0, 1);
+            mTempCalendar.setTimeInMillis(mRangeStartDate.getTimeInMillis());
+            mTempCalendar.setTimeZone(mRangeStartDate.getTimeZone());
             mTempCalendar.add(Calendar.WEEK_OF_YEAR, mWeek);
             if (params.containsKey(VIEW_PARAMS_WEEK_START)) {
                 mTempCalendar.setFirstDayOfWeek(((int[]) params.get(VIEW_PARAMS_WEEK_START))[0]);
@@ -1277,7 +1306,12 @@
 
             for (; i < mNumCells; i++) {
                 mFocusDay[i] = (mTempCalendar.get(Calendar.MONTH) == focusMonth);
-                mDayNumbers[i] = Integer.toString(mTempCalendar.get(Calendar.DAY_OF_MONTH));
+                // do not draw dates outside the valid range to avoid user confusion
+                if (mTempCalendar.before(mRangeStartDate) || mTempCalendar.after(mRangeEndDate)) {
+                    mDayNumbers[i] = "";
+                } else {
+                    mDayNumbers[i] = Integer.toString(mTempCalendar.get(Calendar.DAY_OF_MONTH));
+                }
                 mTempCalendar.add(Calendar.DAY_OF_MONTH, 1);
             }
             // We do one extra add at the end of the loop, if that pushed us to
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 8c22f97..a236d27 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1189,9 +1189,9 @@
      */
     private int getWrappedSelectorIndex(int selectorIndex) {
         if (selectorIndex > mEnd) {
-            return mStart + (selectorIndex - mEnd) % (mEnd - mStart);
+            return mStart + (selectorIndex - mEnd) % (mEnd - mStart) - 1;
         } else if (selectorIndex < mStart) {
-            return mEnd - (mStart - selectorIndex) % (mEnd - mStart);
+            return mEnd - (mStart - selectorIndex) % (mEnd - mStart) + 1;
         }
         return selectorIndex;
     }