Merge "Clean up encapsulation in date picker classes" into lmp-mr1-dev
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 64c81e0..cf3dbab 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -183,8 +183,11 @@
                 mHeaderYearTextView.getTextColors(), R.attr.state_selected,
                 headerSelectedTextColor));
 
-        mDayPickerView = new DayPickerView(mContext, this);
+        mDayPickerView = new DayPickerView(mContext);
+        mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
         mDayPickerView.setRange(mMinDate, mMaxDate);
+        mDayPickerView.setDay(mCurrentDate);
+        mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
 
         mYearPickerView = new YearPickerView(mContext);
         mYearPickerView.init(this);
@@ -333,7 +336,7 @@
 
         switch (viewIndex) {
             case MONTH_AND_DAY_VIEW:
-                mDayPickerView.onDateChanged();
+                mDayPickerView.setDay(getSelectedDay());
                 if (mCurrentView != viewIndex) {
                     mMonthAndDayLayout.setSelected(true);
                     mHeaderYearTextView.setSelected(false);
@@ -445,6 +448,8 @@
     @Override
     public void setFirstDayOfWeek(int firstDayOfWeek) {
         mFirstDayOfWeek = firstDayOfWeek;
+
+        mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
     }
 
     @Override
@@ -606,19 +611,12 @@
         }
     }
 
-    @Override
-    public void onDayOfMonthSelected(int year, int month, int day) {
-        mCurrentDate.set(Calendar.YEAR, year);
-        mCurrentDate.set(Calendar.MONTH, month);
-        mCurrentDate.set(Calendar.DAY_OF_MONTH, day);
-        updatePickers();
-        updateDisplay(true);
-    }
-
     private void updatePickers() {
         for (OnDateChangedListener listener : mListeners) {
             listener.onDateChanged();
         }
+
+        mDayPickerView.setDay(getSelectedDay());
     }
 
     @Override
@@ -627,11 +625,6 @@
     }
 
     @Override
-    public void unregisterOnDateChangedListener(OnDateChangedListener listener) {
-        mListeners.remove(listener);
-    }
-
-    @Override
     public Calendar getSelectedDay() {
         return mCurrentDate;
     }
@@ -652,6 +645,22 @@
     }
 
     /**
+     * Listener called when the user selects a day in the day picker view.
+     */
+    private final DayPickerView.OnDaySelectedListener
+            mOnDaySelectedListener = new DayPickerView.OnDaySelectedListener() {
+        @Override
+        public void onDaySelected(DayPickerView view, Calendar day) {
+            mCurrentDate.setTimeInMillis(day.getTimeInMillis());
+
+            updatePickers();
+            updateDisplay(true);
+
+            tryVibrate();
+        }
+    };
+
+    /**
      * Class for managing state storing/restoring.
      */
     private static class SavedState extends View.BaseSavedState {
diff --git a/core/java/android/widget/DatePickerController.java b/core/java/android/widget/DatePickerController.java
index ea6ec61..8f809ba 100644
--- a/core/java/android/widget/DatePickerController.java
+++ b/core/java/android/widget/DatePickerController.java
@@ -27,16 +27,9 @@
 
     void onYearSelected(int year);
 
-    void onDayOfMonthSelected(int year, int month, int day);
-
     void registerOnDateChangedListener(OnDateChangedListener listener);
 
-    void unregisterOnDateChangedListener(OnDateChangedListener listener);
-
     Calendar getSelectedDay();
 
-    void setFirstDayOfWeek(int firstDayOfWeek);
-    int getFirstDayOfWeek();
-
     void tryVibrate();
 }
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index f9544d0..6cb1c9d 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -16,14 +16,10 @@
 
 package android.widget;
 
-import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
-import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
-import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
 import android.view.View;
@@ -38,9 +34,7 @@
 /**
  * This displays a list of months in a calendar format with selectable days.
  */
-class DayPickerView extends ListView implements AbsListView.OnScrollListener,
-        OnDateChangedListener {
-
+class DayPickerView extends ListView implements AbsListView.OnScrollListener {
     private static final String TAG = "DayPickerView";
 
     // How long the GoTo fling animation should last
@@ -49,20 +43,22 @@
     // How long to wait after receiving an onScrollStateChanged notification before acting on it
     private static final int SCROLL_CHANGE_DELAY = 40;
 
-    private static int LIST_TOP_OFFSET = -1; // so that the top line will be under the separator
+    // so that the top line will be under the separator
+    private static final int LIST_TOP_OFFSET = -1;
+
+    private final SimpleMonthAdapter mAdapter = new SimpleMonthAdapter(getContext());
+
+    private final ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(this);
 
     private SimpleDateFormat mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
 
-    // These affect the scroll speed and feel
-    private float mFriction = 1.0f;
-
     // highlighted time
     private Calendar mSelectedDay = Calendar.getInstance();
     private Calendar mTempDay = Calendar.getInstance();
     private Calendar mMinDate = Calendar.getInstance();
     private Calendar mMaxDate = Calendar.getInstance();
 
-    private SimpleMonthAdapter mAdapter;
+    private OnDaySelectedListener mOnDaySelectedListener;
 
     // which month should be displayed/highlighted [0-11]
     private int mCurrentMonthDisplayed;
@@ -71,34 +67,27 @@
     // used for tracking what state listview is in
     private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE;
 
-    private DatePickerController mController;
     private boolean mPerformingScroll;
 
-    private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(this);
-
-    public DayPickerView(Context context, DatePickerController controller) {
+    public DayPickerView(Context context) {
         super(context);
 
-        init();
-        setController(controller);
-    }
-
-    public void setController(DatePickerController controller) {
-        if (mController != null) {
-            mController.unregisterOnDateChangedListener(this);
-        }
-        mController = controller;
-        mController.registerOnDateChangedListener(this);
-        setUpAdapter();
         setAdapter(mAdapter);
-        onDateChanged();
-    }
-
-    public void init() {
         setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
         setDrawSelectorOnTop(false);
-
         setUpListView();
+
+        goTo(mSelectedDay, false, true, true);
+
+        mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
+    }
+
+    public void setDay(Calendar day) {
+        goTo(day, false, true, true);
+    }
+
+    public void setFirstDayOfWeek(int firstDayOfWeek) {
+        mAdapter.setFirstDayOfWeek(firstDayOfWeek);
     }
 
     public void setRange(Calendar minDate, Calendar maxDate) {
@@ -113,54 +102,19 @@
     }
 
     /**
-     * Constrains the supplied calendar to stay within the min and max
-     * calendars, returning <code>true</code> if the supplied calendar
-     * was modified.
+     * Sets the listener to call when the user selects a day.
      *
-     * @param value The calendar to constrain
-     * @param min The minimum calendar
-     * @param max The maximum calendar
-     * @return True if <code>value</code> was modified
+     * @param listener The listener to call.
      */
-    private boolean constrainCalendar(Calendar value, Calendar min, Calendar max) {
-        if (value.compareTo(min) < 0) {
-            value.setTimeInMillis(min.getTimeInMillis());
-            return true;
-        }
-
-        if (value.compareTo(max) > 0) {
-            value.setTimeInMillis(max.getTimeInMillis());
-            return true;
-        }
-
-        return false;
-    }
-
-    public void onChange() {
-        setUpAdapter();
-        setAdapter(mAdapter);
-    }
-
-    /**
-     * Creates a new adapter if necessary and sets up its parameters. Override
-     * this method to provide a custom adapter.
-     */
-    protected void setUpAdapter() {
-        if (mAdapter == null) {
-            mAdapter = new SimpleMonthAdapter(getContext(), mController);
-        } else {
-            mAdapter.setSelectedDay(mSelectedDay);
-            mAdapter.notifyDataSetChanged();
-        }
-        // refresh the view with the new parameters
-        mAdapter.notifyDataSetChanged();
+    public void setOnDaySelectedListener(OnDaySelectedListener listener) {
+        mOnDaySelectedListener = listener;
     }
 
     /*
      * Sets all the required fields for the list view. Override this method to
      * set a different list view behavior.
      */
-    protected void setUpListView() {
+    private void setUpListView() {
         // Transparent background on scroll
         setCacheColorHint(0);
         // No dividers
@@ -173,7 +127,7 @@
         setOnScrollListener(this);
         setFadingEdgeLength(0);
         // Make the scrolling behavior nicer
-        setFriction(ViewConfiguration.getScrollFriction() * mFriction);
+        setFriction(ViewConfiguration.getScrollFriction());
     }
 
     private int getDiffMonths(Calendar start, Calendar end) {
@@ -203,7 +157,7 @@
      *            visible
      * @return Whether or not the view animated to the new location
      */
-    public boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) {
+    private boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) {
 
         // Set the selected day
         if (setSelected) {
@@ -392,11 +346,6 @@
         return firstPosition + mostVisibleIndex;
     }
 
-    @Override
-    public void onDateChanged() {
-        goTo(mController.getSelectedDay(), false, true, true);
-    }
-
     /**
      * Attempts to return the date that has accessibility focus.
      *
@@ -529,4 +478,18 @@
         mPerformingScroll = true;
         return true;
     }
+
+    public interface OnDaySelectedListener {
+        public void onDaySelected(DayPickerView view, Calendar day);
+    }
+
+    private final SimpleMonthAdapter.OnDaySelectedListener
+            mProxyOnDaySelectedListener = new SimpleMonthAdapter.OnDaySelectedListener() {
+        @Override
+        public void onDaySelected(SimpleMonthAdapter adapter, Calendar day) {
+            if (mOnDaySelectedListener != null) {
+                mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
+            }
+        }
+    };
 }
diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java
index 5aa78c8..ecd2912 100644
--- a/core/java/android/widget/SimpleMonthAdapter.java
+++ b/core/java/android/widget/SimpleMonthAdapter.java
@@ -20,29 +20,28 @@
 import android.content.res.ColorStateList;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.SimpleMonthView.OnDayClickListener;
 
 import java.util.Calendar;
-import java.util.HashMap;
 
 /**
  * An adapter for a list of {@link android.widget.SimpleMonthView} items.
  */
-class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayClickListener {
+class SimpleMonthAdapter extends BaseAdapter {
     private final Calendar mMinDate = Calendar.getInstance();
     private final Calendar mMaxDate = Calendar.getInstance();
 
     private final Context mContext;
-    private final DatePickerController mController;
 
     private Calendar mSelectedDay;
     private ColorStateList mCalendarTextColors;
+    private OnDaySelectedListener mOnDaySelectedListener;
 
-    public SimpleMonthAdapter(Context context, DatePickerController controller) {
+    private int mFirstDayOfWeek;
+
+    public SimpleMonthAdapter(Context context) {
         mContext = context;
-        mController = controller;
-
-        init();
-        setSelectedDay(mController.getSelectedDay());
+        mSelectedDay = Calendar.getInstance();
     }
 
     public void setRange(Calendar min, Calendar max) {
@@ -52,29 +51,36 @@
         notifyDataSetInvalidated();
     }
 
+    public void setFirstDayOfWeek(int firstDayOfWeek) {
+        mFirstDayOfWeek = firstDayOfWeek;
+
+        notifyDataSetInvalidated();
+    }
+
     /**
      * Updates the selected day and related parameters.
      *
      * @param day The day to highlight
      */
     public void setSelectedDay(Calendar day) {
-        if (mSelectedDay != day) {
-            mSelectedDay = day;
-            notifyDataSetChanged();
-        }
+        mSelectedDay = day;
+
+        notifyDataSetChanged();
+    }
+
+    /**
+     * Sets the listener to call when the user selects a day.
+     *
+     * @param listener The listener to call.
+     */
+    public void setOnDaySelectedListener(OnDaySelectedListener listener) {
+        mOnDaySelectedListener = listener;
     }
 
     void setCalendarTextColor(ColorStateList colors) {
         mCalendarTextColors = colors;
     }
 
-    /**
-     * Set up the gesture detector and selected time
-     */
-    protected void init() {
-        mSelectedDay = Calendar.getInstance();
-    }
-
     @Override
     public int getCount() {
         final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
@@ -111,7 +117,7 @@
                     AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
             v.setLayoutParams(params);
             v.setClickable(true);
-            v.setOnDayClickListener(this);
+            v.setOnDayClickListener(mOnDayClickListener);
 
             if (mCalendarTextColors != null) {
                 v.setTextColor(mCalendarTextColors);
@@ -148,7 +154,7 @@
             enabledDayRangeEnd = 31;
         }
 
-        v.setMonthParams(selectedDay, month, year, mController.getFirstDayOfWeek(),
+        v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
                 enabledDayRangeStart, enabledDayRangeEnd);
         v.invalidate();
 
@@ -159,27 +165,24 @@
         return mSelectedDay.get(Calendar.YEAR) == year && mSelectedDay.get(Calendar.MONTH) == month;
     }
 
-    @Override
-    public void onDayClick(SimpleMonthView view, Calendar day) {
-        if (day != null && isCalendarInRange(day)) {
-            onDaySelected(day);
-        }
-    }
-
     private boolean isCalendarInRange(Calendar value) {
         return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
     }
 
-    /**
-     * Maintains the same hour/min/sec but moves the day to the tapped day.
-     *
-     * @param day The day that was tapped
-     */
-    private void onDaySelected(Calendar day) {
-        mController.tryVibrate();
-        mController.onDayOfMonthSelected(day.get(Calendar.YEAR), day.get(Calendar.MONTH),
-                day.get(Calendar.DAY_OF_MONTH));
+    private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
+        @Override
+        public void onDayClick(SimpleMonthView view, Calendar day) {
+            if (day != null && isCalendarInRange(day)) {
+                setSelectedDay(day);
 
-        setSelectedDay(day);
+                if (mOnDaySelectedListener != null) {
+                    mOnDaySelectedListener.onDaySelected(SimpleMonthAdapter.this, day);
+                }
+            }
+        }
+    };
+
+    public interface OnDaySelectedListener {
+        public void onDaySelected(SimpleMonthAdapter view, Calendar day);
     }
 }