13e9818e0267619fecebd55095ab26c53eff92e93James Kung/*
23e9818e0267619fecebd55095ab26c53eff92e93James Kung * Copyright (C) 2013 The Android Open Source Project
33e9818e0267619fecebd55095ab26c53eff92e93James Kung *
43e9818e0267619fecebd55095ab26c53eff92e93James Kung * Licensed under the Apache License, Version 2.0 (the "License");
53e9818e0267619fecebd55095ab26c53eff92e93James Kung * you may not use this file except in compliance with the License.
63e9818e0267619fecebd55095ab26c53eff92e93James Kung * You may obtain a copy of the License at
73e9818e0267619fecebd55095ab26c53eff92e93James Kung *
83e9818e0267619fecebd55095ab26c53eff92e93James Kung *      http://www.apache.org/licenses/LICENSE-2.0
93e9818e0267619fecebd55095ab26c53eff92e93James Kung *
103e9818e0267619fecebd55095ab26c53eff92e93James Kung * Unless required by applicable law or agreed to in writing, software
113e9818e0267619fecebd55095ab26c53eff92e93James Kung * distributed under the License is distributed on an "AS IS" BASIS,
123e9818e0267619fecebd55095ab26c53eff92e93James Kung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e9818e0267619fecebd55095ab26c53eff92e93James Kung * See the License for the specific language governing permissions and
143e9818e0267619fecebd55095ab26c53eff92e93James Kung * limitations under the License.
153e9818e0267619fecebd55095ab26c53eff92e93James Kung */
163e9818e0267619fecebd55095ab26c53eff92e93James Kung
173e9818e0267619fecebd55095ab26c53eff92e93James Kungpackage com.android.datetimepicker.date;
183e9818e0267619fecebd55095ab26c53eff92e93James Kung
193e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.content.Context;
202e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.content.res.Resources;
212e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.graphics.drawable.StateListDrawable;
22cb3f2522609186db6239ad154af275957118295cSam Blitzsteinimport android.util.Log;
232e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.view.View;
243e9818e0267619fecebd55095ab26c53eff92e93James Kungimport android.view.ViewGroup;
25cb3f2522609186db6239ad154af275957118295cSam Blitzsteinimport android.view.accessibility.AccessibilityEvent;
262e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.widget.AdapterView;
272e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.widget.AdapterView.OnItemClickListener;
282e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.widget.ArrayAdapter;
292e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.widget.ListView;
302e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport android.widget.TextView;
312e00aa34c051111529290cf23c6ba940c2c0c142James Kung
322e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport com.android.datetimepicker.R;
33cb3f2522609186db6239ad154af275957118295cSam Blitzsteinimport com.android.datetimepicker.Utils;
342e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport com.android.datetimepicker.date.DatePickerDialog.OnDateChangedListener;
352e00aa34c051111529290cf23c6ba940c2c0c142James Kung
362e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport java.util.ArrayList;
372e00aa34c051111529290cf23c6ba940c2c0c142James Kungimport java.util.List;
383e9818e0267619fecebd55095ab26c53eff92e93James Kung
393e9818e0267619fecebd55095ab26c53eff92e93James Kung/**
402e00aa34c051111529290cf23c6ba940c2c0c142James Kung * Displays a selectable list of years.
413e9818e0267619fecebd55095ab26c53eff92e93James Kung */
422e00aa34c051111529290cf23c6ba940c2c0c142James Kungpublic class YearPickerView extends ListView implements OnItemClickListener, OnDateChangedListener {
43cb3f2522609186db6239ad154af275957118295cSam Blitzstein    private static final String TAG = "YearPickerView";
443e9818e0267619fecebd55095ab26c53eff92e93James Kung
453e9818e0267619fecebd55095ab26c53eff92e93James Kung    private final DatePickerController mController;
462e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private YearAdapter mAdapter;
472e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private int mViewSize;
482e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private int mChildSize;
492e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private TextViewWithCircularIndicator mSelectedView;
503e9818e0267619fecebd55095ab26c53eff92e93James Kung
512e00aa34c051111529290cf23c6ba940c2c0c142James Kung    /**
522e00aa34c051111529290cf23c6ba940c2c0c142James Kung     * @param context
532e00aa34c051111529290cf23c6ba940c2c0c142James Kung     */
543e9818e0267619fecebd55095ab26c53eff92e93James Kung    public YearPickerView(Context context, DatePickerController controller) {
553e9818e0267619fecebd55095ab26c53eff92e93James Kung        super(context);
563e9818e0267619fecebd55095ab26c53eff92e93James Kung        mController = controller;
572e00aa34c051111529290cf23c6ba940c2c0c142James Kung        mController.registerOnDateChangedListener(this);
583e9818e0267619fecebd55095ab26c53eff92e93James Kung        ViewGroup.LayoutParams frame = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,
593e9818e0267619fecebd55095ab26c53eff92e93James Kung                LayoutParams.WRAP_CONTENT);
602e00aa34c051111529290cf23c6ba940c2c0c142James Kung        setLayoutParams(frame);
612e00aa34c051111529290cf23c6ba940c2c0c142James Kung        Resources res = context.getResources();
6251da77ac265fc6e46403bc6f8d3cca57e57427d7James Kung        mViewSize = res.getDimensionPixelOffset(R.dimen.date_picker_view_animator_height);
632e00aa34c051111529290cf23c6ba940c2c0c142James Kung        mChildSize = res.getDimensionPixelOffset(R.dimen.year_label_height);
6451da77ac265fc6e46403bc6f8d3cca57e57427d7James Kung        setVerticalFadingEdgeEnabled(true);
652e00aa34c051111529290cf23c6ba940c2c0c142James Kung        setFadingEdgeLength(mChildSize / 3);
662e00aa34c051111529290cf23c6ba940c2c0c142James Kung        init(context);
672e00aa34c051111529290cf23c6ba940c2c0c142James Kung        setOnItemClickListener(this);
682e00aa34c051111529290cf23c6ba940c2c0c142James Kung        setSelector(new StateListDrawable());
692e00aa34c051111529290cf23c6ba940c2c0c142James Kung        setDividerHeight(0);
702e00aa34c051111529290cf23c6ba940c2c0c142James Kung        onDateChanged();
712e00aa34c051111529290cf23c6ba940c2c0c142James Kung    }
722e00aa34c051111529290cf23c6ba940c2c0c142James Kung
732e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private void init(Context context) {
742e00aa34c051111529290cf23c6ba940c2c0c142James Kung        ArrayList<String> years = new ArrayList<String>();
752e00aa34c051111529290cf23c6ba940c2c0c142James Kung        for (int year = mController.getMinYear(); year <= mController.getMaxYear(); year++) {
76e0bbee5b271a9439335c002e09a70de8c083568dSam Blitzstein            years.add(String.format("%d", year));
772e00aa34c051111529290cf23c6ba940c2c0c142James Kung        }
782e00aa34c051111529290cf23c6ba940c2c0c142James Kung        mAdapter = new YearAdapter(context, R.layout.year_label_text_view, years);
792e00aa34c051111529290cf23c6ba940c2c0c142James Kung        setAdapter(mAdapter);
802e00aa34c051111529290cf23c6ba940c2c0c142James Kung    }
812e00aa34c051111529290cf23c6ba940c2c0c142James Kung
822e00aa34c051111529290cf23c6ba940c2c0c142James Kung    @Override
832e00aa34c051111529290cf23c6ba940c2c0c142James Kung    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
842e00aa34c051111529290cf23c6ba940c2c0c142James Kung        mController.tryVibrate();
852e00aa34c051111529290cf23c6ba940c2c0c142James Kung        TextViewWithCircularIndicator clickedView = (TextViewWithCircularIndicator) view;
8671492ab60892087f3e989b876b82f5c0249b3b14James Kung        if (clickedView != null) {
8771492ab60892087f3e989b876b82f5c0249b3b14James Kung            if (clickedView != mSelectedView) {
8871492ab60892087f3e989b876b82f5c0249b3b14James Kung                if (mSelectedView != null) {
8971492ab60892087f3e989b876b82f5c0249b3b14James Kung                    mSelectedView.drawIndicator(false);
9071492ab60892087f3e989b876b82f5c0249b3b14James Kung                    mSelectedView.requestLayout();
9171492ab60892087f3e989b876b82f5c0249b3b14James Kung                }
9271492ab60892087f3e989b876b82f5c0249b3b14James Kung                clickedView.drawIndicator(true);
9371492ab60892087f3e989b876b82f5c0249b3b14James Kung                clickedView.requestLayout();
9471492ab60892087f3e989b876b82f5c0249b3b14James Kung                mSelectedView = clickedView;
9571492ab60892087f3e989b876b82f5c0249b3b14James Kung            }
9671492ab60892087f3e989b876b82f5c0249b3b14James Kung            mController.onYearSelected(getYearFromTextView(clickedView));
9771492ab60892087f3e989b876b82f5c0249b3b14James Kung            mAdapter.notifyDataSetChanged();
982e00aa34c051111529290cf23c6ba940c2c0c142James Kung        }
993e9818e0267619fecebd55095ab26c53eff92e93James Kung    }
1003e9818e0267619fecebd55095ab26c53eff92e93James Kung
1012e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private int getYearFromTextView(TextView view) {
1022e00aa34c051111529290cf23c6ba940c2c0c142James Kung        return Integer.valueOf(view.getText().toString());
1033e9818e0267619fecebd55095ab26c53eff92e93James Kung    }
1043e9818e0267619fecebd55095ab26c53eff92e93James Kung
1052e00aa34c051111529290cf23c6ba940c2c0c142James Kung    private class YearAdapter extends ArrayAdapter<String> {
1062e00aa34c051111529290cf23c6ba940c2c0c142James Kung
1072e00aa34c051111529290cf23c6ba940c2c0c142James Kung        public YearAdapter(Context context, int resource, List<String> objects) {
1082e00aa34c051111529290cf23c6ba940c2c0c142James Kung            super(context, resource, objects);
1092e00aa34c051111529290cf23c6ba940c2c0c142James Kung        }
1102e00aa34c051111529290cf23c6ba940c2c0c142James Kung
1112e00aa34c051111529290cf23c6ba940c2c0c142James Kung        @Override
1122e00aa34c051111529290cf23c6ba940c2c0c142James Kung        public View getView(int position, View convertView, ViewGroup parent) {
1132e00aa34c051111529290cf23c6ba940c2c0c142James Kung            TextViewWithCircularIndicator v = (TextViewWithCircularIndicator)
1142e00aa34c051111529290cf23c6ba940c2c0c142James Kung                    super.getView(position, convertView, parent);
1152e00aa34c051111529290cf23c6ba940c2c0c142James Kung            v.requestLayout();
1162e00aa34c051111529290cf23c6ba940c2c0c142James Kung            int year = getYearFromTextView(v);
1172e00aa34c051111529290cf23c6ba940c2c0c142James Kung            boolean selected = mController.getSelectedDay().year == year;
1182e00aa34c051111529290cf23c6ba940c2c0c142James Kung            v.drawIndicator(selected);
1192e00aa34c051111529290cf23c6ba940c2c0c142James Kung            if (selected) {
1202e00aa34c051111529290cf23c6ba940c2c0c142James Kung                mSelectedView = v;
1212e00aa34c051111529290cf23c6ba940c2c0c142James Kung            }
1222e00aa34c051111529290cf23c6ba940c2c0c142James Kung            return v;
1232e00aa34c051111529290cf23c6ba940c2c0c142James Kung        }
1242e00aa34c051111529290cf23c6ba940c2c0c142James Kung    }
1252e00aa34c051111529290cf23c6ba940c2c0c142James Kung
12671492ab60892087f3e989b876b82f5c0249b3b14James Kung    public void postSetSelectionCentered(final int position) {
12771492ab60892087f3e989b876b82f5c0249b3b14James Kung        postSetSelectionFromTop(position, mViewSize / 2 - mChildSize / 2);
1282e00aa34c051111529290cf23c6ba940c2c0c142James Kung    }
1292e00aa34c051111529290cf23c6ba940c2c0c142James Kung
13071492ab60892087f3e989b876b82f5c0249b3b14James Kung    public void postSetSelectionFromTop(final int position, final int offset) {
1312e00aa34c051111529290cf23c6ba940c2c0c142James Kung        post(new Runnable() {
1322e00aa34c051111529290cf23c6ba940c2c0c142James Kung
1332e00aa34c051111529290cf23c6ba940c2c0c142James Kung            @Override
1342e00aa34c051111529290cf23c6ba940c2c0c142James Kung            public void run() {
13571492ab60892087f3e989b876b82f5c0249b3b14James Kung                setSelectionFromTop(position, offset);
1362e00aa34c051111529290cf23c6ba940c2c0c142James Kung                requestLayout();
1372e00aa34c051111529290cf23c6ba940c2c0c142James Kung            }
1382e00aa34c051111529290cf23c6ba940c2c0c142James Kung        });
1393e9818e0267619fecebd55095ab26c53eff92e93James Kung    }
1403e9818e0267619fecebd55095ab26c53eff92e93James Kung
14171492ab60892087f3e989b876b82f5c0249b3b14James Kung    public int getFirstPositionOffset() {
14271492ab60892087f3e989b876b82f5c0249b3b14James Kung        final View firstChild = getChildAt(0);
14371492ab60892087f3e989b876b82f5c0249b3b14James Kung        if (firstChild == null) {
14471492ab60892087f3e989b876b82f5c0249b3b14James Kung            return 0;
14571492ab60892087f3e989b876b82f5c0249b3b14James Kung        }
14671492ab60892087f3e989b876b82f5c0249b3b14James Kung        return firstChild.getTop();
14771492ab60892087f3e989b876b82f5c0249b3b14James Kung    }
14871492ab60892087f3e989b876b82f5c0249b3b14James Kung
1493e9818e0267619fecebd55095ab26c53eff92e93James Kung    @Override
1502e00aa34c051111529290cf23c6ba940c2c0c142James Kung    public void onDateChanged() {
1512e00aa34c051111529290cf23c6ba940c2c0c142James Kung        mAdapter.notifyDataSetChanged();
15271492ab60892087f3e989b876b82f5c0249b3b14James Kung        postSetSelectionCentered(mController.getSelectedDay().year - mController.getMinYear());
1533e9818e0267619fecebd55095ab26c53eff92e93James Kung    }
154cb3f2522609186db6239ad154af275957118295cSam Blitzstein
155cb3f2522609186db6239ad154af275957118295cSam Blitzstein    @Override
156cb3f2522609186db6239ad154af275957118295cSam Blitzstein    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
157cb3f2522609186db6239ad154af275957118295cSam Blitzstein        super.onInitializeAccessibilityEvent(event);
158cb3f2522609186db6239ad154af275957118295cSam Blitzstein        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
159cb3f2522609186db6239ad154af275957118295cSam Blitzstein            event.setFromIndex(0);
160cb3f2522609186db6239ad154af275957118295cSam Blitzstein            event.setToIndex(0);
161cb3f2522609186db6239ad154af275957118295cSam Blitzstein        }
162cb3f2522609186db6239ad154af275957118295cSam Blitzstein    }
1633e9818e0267619fecebd55095ab26c53eff92e93James Kung}
164