summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRohit Yengisetty <rohit@cyngn.com>2014-11-26 19:18:49 -0800
committerSteve Kondik <steve@cyngn.com>2015-10-18 13:52:41 -0700
commit7b95358fdd3f9759a70fb4d27f2d2be4c5f796c6 (patch)
treee097afc5c52f2269436e70a7ea5ced2062017e18 /src
parent990c61ad0a076a13598660b7fa477e6c30f7b783 (diff)
downloadandroid_packages_apps_Calendar-7b95358fdd3f9759a70fb4d27f2d2be4c5f796c6.tar.gz
android_packages_apps_Calendar-7b95358fdd3f9759a70fb4d27f2d2be4c5f796c6.tar.bz2
android_packages_apps_Calendar-7b95358fdd3f9759a70fb4d27f2d2be4c5f796c6.zip
Calendar : Adding Year View
Depends on changes to datetimepicker @ http://review.cyanogenmod.org/#/c/79480/ Change-Id: Ie528d8c1753477b94a9c477f5735a198565afd4d
Diffstat (limited to 'src')
-rw-r--r--src/com/android/calendar/AllInOneActivity.java27
-rw-r--r--src/com/android/calendar/CalendarController.java5
-rw-r--r--src/com/android/calendar/CalendarViewAdapter.java24
-rw-r--r--src/com/android/calendar/year/YearViewAdapter.java319
-rw-r--r--src/com/android/calendar/year/YearViewPagerFragment.java253
5 files changed, 624 insertions, 4 deletions
diff --git a/src/com/android/calendar/AllInOneActivity.java b/src/com/android/calendar/AllInOneActivity.java
index fcf2b0cd..7bcb6772 100644
--- a/src/com/android/calendar/AllInOneActivity.java
+++ b/src/com/android/calendar/AllInOneActivity.java
@@ -80,6 +80,7 @@ import com.android.calendar.CalendarController.ViewType;
import com.android.calendar.agenda.AgendaFragment;
import com.android.calendar.month.MonthByWeekFragment;
import com.android.calendar.selectcalendars.SelectVisibleCalendarsFragment;
+import com.android.calendar.year.YearViewPagerFragment;
import java.io.File;
import java.io.IOException;
@@ -113,6 +114,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
private static final int BUTTON_WEEK_INDEX = 1;
private static final int BUTTON_MONTH_INDEX = 2;
private static final int BUTTON_AGENDA_INDEX = 3;
+ private static final int BUTTON_YEAR_INDEX = 4;
private CalendarController mController;
private static boolean mIsMultipane;
@@ -156,6 +158,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
private ActionBar.Tab mDayTab;
private ActionBar.Tab mWeekTab;
private ActionBar.Tab mMonthTab;
+ private ActionBar.Tab mYearTab;
private ActionBar.Tab mAgendaTab;
private SearchView mSearchView;
private MenuItem mSearchMenu;
@@ -505,6 +508,9 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
case ViewType.MONTH:
mActionBar.setSelectedNavigationItem(BUTTON_MONTH_INDEX);
break;
+ case ViewType.YEAR:
+ mActionBar.setSelectedNavigationItem(BUTTON_YEAR_INDEX);
+ break;
default:
mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX);
break;
@@ -988,6 +994,16 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
}
ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView("month");
break;
+ case ViewType.YEAR:
+ if (mActionBar != null && (mActionBar.getSelectedTab() != mYearTab)) {
+ mActionBar.selectTab(mYearTab);
+ }
+ if (mActionBarMenuSpinnerAdapter != null) {
+ mActionBar.setSelectedNavigationItem(CalendarViewAdapter.YEAR_BUTTON_INDEX);
+ }
+ frag = new YearViewPagerFragment(timeMillis);
+ ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView("year");
+ break;
case ViewType.WEEK:
default:
if (mActionBar != null && (mActionBar.getSelectedTab() != mWeekTab)) {
@@ -1328,13 +1344,15 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK);
} else if (tab == mMonthTab && mCurrentView != ViewType.MONTH) {
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH);
+ } else if (tab == mYearTab && mCurrentView != ViewType.YEAR) {
+ mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.YEAR);
} else if (tab == mAgendaTab && mCurrentView != ViewType.AGENDA) {
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA);
} else {
Log.w(TAG, "TabSelected event from unknown tab: "
+ (tab == null ? "null" : tab.getText()));
Log.w(TAG, "CurrentView:" + mCurrentView + " Tab:" + tab.toString() + " Day:" + mDayTab
- + " Week:" + mWeekTab + " Month:" + mMonthTab + " Agenda:" + mAgendaTab);
+ + " Week:" + mWeekTab + " Month:" + mMonthTab + " Year:" + mYearTab + " Agenda:" + mAgendaTab);
}
}
@@ -1365,6 +1383,11 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH);
}
break;
+ case CalendarViewAdapter.YEAR_BUTTON_INDEX:
+ if (mCurrentView != ViewType.YEAR) {
+ mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.YEAR);
+ }
+ break;
case CalendarViewAdapter.AGENDA_BUTTON_INDEX:
if (mCurrentView != ViewType.AGENDA) {
mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA);
@@ -1374,7 +1397,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH
Log.w(TAG, "ItemSelected event from unknown button: " + itemPosition);
Log.w(TAG, "CurrentView:" + mCurrentView + " Button:" + itemPosition +
" Day:" + mDayTab + " Week:" + mWeekTab + " Month:" + mMonthTab +
- " Agenda:" + mAgendaTab);
+ " Year:" + mYearTab + " Agenda:" + mAgendaTab);
break;
}
return false;
diff --git a/src/com/android/calendar/CalendarController.java b/src/com/android/calendar/CalendarController.java
index 93b1b489..fd5392f1 100644
--- a/src/com/android/calendar/CalendarController.java
+++ b/src/com/android/calendar/CalendarController.java
@@ -130,7 +130,7 @@ public class CalendarController {
}
/**
- * One of the Agenda/Day/Week/Month view types
+ * One of the Agenda/Day/Week/Month/Year view types
*/
public interface ViewType {
final int DETAIL = -1;
@@ -140,7 +140,8 @@ public class CalendarController {
final int WEEK = 3;
final int MONTH = 4;
final int EDIT = 5;
- final int MAX_VALUE = 5;
+ final int YEAR = 6;
+ final int MAX_VALUE = 6;
}
public static class EventInfo {
diff --git a/src/com/android/calendar/CalendarViewAdapter.java b/src/com/android/calendar/CalendarViewAdapter.java
index a2aaae0a..fa9bab4d 100644
--- a/src/com/android/calendar/CalendarViewAdapter.java
+++ b/src/com/android/calendar/CalendarViewAdapter.java
@@ -32,9 +32,12 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.Date;
import java.util.Formatter;
import java.util.Locale;
+import java.util.TimeZone;
/*
@@ -67,6 +70,7 @@ public class CalendarViewAdapter extends BaseAdapter {
public static final int WEEK_BUTTON_INDEX = 1;
public static final int MONTH_BUTTON_INDEX = 2;
public static final int AGENDA_BUTTON_INDEX = 3;
+ public static final int YEAR_BUTTON_INDEX = 4;
// The current selected event's time, used to calculate the date and day of the week
// for the buttons.
@@ -245,6 +249,11 @@ public class CalendarViewAdapter extends BaseAdapter {
weekDay.setText(buildDayOfWeek());
date.setText(buildFullDate());
break;
+ case ViewType.YEAR:
+ weekDay.setVisibility(View.GONE);
+ lunarInfo.setVisibility(View.GONE);
+ date.setText(buildYearDate());
+ break;
default:
v = null;
break;
@@ -271,6 +280,9 @@ public class CalendarViewAdapter extends BaseAdapter {
case ViewType.MONTH:
title.setText(mButtonNames [MONTH_BUTTON_INDEX]);
break;
+ case ViewType.YEAR:
+ title.setText(mButtonNames [YEAR_BUTTON_INDEX]);
+ break;
case ViewType.AGENDA:
title.setText(mButtonNames [AGENDA_BUTTON_INDEX]);
break;
@@ -328,6 +340,12 @@ public class CalendarViewAdapter extends BaseAdapter {
date.setText(buildMonthDayDate());
}
break;
+ case YEAR_BUTTON_INDEX:
+ viewType.setText(mButtonNames [YEAR_BUTTON_INDEX]);
+ if (mShowDate) {
+ date.setText(buildYearDate());
+ }
+ break;
default:
v = convertView;
break;
@@ -394,6 +412,12 @@ public class CalendarViewAdapter extends BaseAdapter {
return date;
}
+ private String buildYearDate() {
+ SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
+ yearFormat.setTimeZone(TimeZone.getTimeZone(mTimeZone));
+ return yearFormat.format(new Date(mMilliTime));
+ }
+
private String buildMonthYearDate() {
mStringBuilder.setLength(0);
String date = DateUtils.formatDateRange(
diff --git a/src/com/android/calendar/year/YearViewAdapter.java b/src/com/android/calendar/year/YearViewAdapter.java
new file mode 100644
index 00000000..f4bd4964
--- /dev/null
+++ b/src/com/android/calendar/year/YearViewAdapter.java
@@ -0,0 +1,319 @@
+package com.android.calendar.year;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import com.android.calendar.CalendarController;
+import com.android.calendar.CalendarController.EventType;
+import com.android.calendar.R;
+import com.android.datetimepicker.date.MonthView;
+
+import java.util.HashMap;
+
+/**
+ * Adapter class used to display an entire year as a sequence of month views
+ */
+public class YearViewAdapter extends BaseAdapter implements View.OnTouchListener {
+
+ /* Define configuration parameters for a month view */
+ // fraction of the view occupied by the header
+ private static final double MONTH_HEADER_HEIGHT = 0.30;
+
+ // fraction of the header to use for the month title text
+ private static final double MONTH_LABEL_FONT_SIZE = MONTH_HEADER_HEIGHT * 0.30;
+
+ // fraction of the view to use as padding along one edge
+ private static final double PADDING = 0.05;
+
+ // fraction of the view to use for text
+ private static final double MONTH_DAY_TEXT_SIZE = (1 - (2 * PADDING)) * (0.7) / 7;
+
+ // The padding b/w the week rows. The container height sans that taken up by the header
+ // is equally distributed among six rows
+ private static final double ROW_HEIGHT = (1 - MONTH_HEADER_HEIGHT) / 6;
+
+ private static final int NUMBER_OF_MONTHS = 12;
+
+ /* Instance Variables */
+ private final Context mContext;
+ private CalendarController mController;
+ private int mYear;
+ private int mCurrentMonth = -1;
+
+ private int mColumns; // number of columns the months will be dispersed into
+ private int mWidth; // dimensions of the container housing the entire year view
+ private int mHeight;
+ private int mMonthWidth; // dimensions of each month inside the year view
+ private int mMonthHeight;
+ private int mCurrentMonthBgColor;
+ private int mMonthTitleColor;
+ private int mMonthClickColor;
+ private int mCurrentDayColor;
+
+ private View mClickedView;
+ private long mClickTimestamp;
+ private long mClickAnimDuration = ViewConfiguration.getTapTimeout() + 100;
+ private int mTouchSlop; // threshold for click to scroll transition
+ private float mClickX; // initial ACTION_DOWN coordinates
+ private float mClickY;
+
+ public YearViewAdapter(Context context, int year, int columns) {
+ mContext = context;
+ mController = CalendarController.getInstance(mContext);
+ mYear = year;
+ mColumns = columns;
+
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ mMonthTitleColor = mContext.getResources().getColor(R.color.year_view_month_title_color);
+ mMonthClickColor = mContext.getResources().getColor(R.color.year_view_month_click_color);
+ mCurrentDayColor = mContext.getResources().getColor(R.color.year_view_current_day_color);
+ mCurrentMonthBgColor =
+ mContext.getResources().getColor(R.color.year_view_current_month_bg_color);
+ }
+
+ /**
+ * Sets the container bounds that the entire year view can occupy.
+ * Drawing parameters are calculated based off these bounds
+ *
+ * @param width max width of the parent container
+ * @param height max height of the parent container
+ */
+ public void setBounds(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ // calculate the dimensions of each of the months
+ mMonthWidth = mWidth / mColumns;
+ mMonthHeight = mHeight / (NUMBER_OF_MONTHS / mColumns);
+ }
+
+ @Override
+ public int getCount() {
+ return NUMBER_OF_MONTHS;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ /**
+ * Generates a month view
+ *
+ */
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int month = position;
+ // each month view is nested inside a linear layout
+ GreedyLinearLayout linearLayout = new GreedyLinearLayout(mContext);
+ AbsListView.LayoutParams params = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, mMonthHeight);
+ linearLayout.setLayoutParams(params);
+ linearLayout.setId(month);
+ linearLayout.setOnTouchListener(this);
+ Time now = new Time();
+ now.setToNow();
+ if (now.month == month && now.year == mYear) {
+ mCurrentMonth = month;
+ linearLayout.setBackgroundColor(mCurrentMonthBgColor);
+ }
+
+ // the view that actually draws the calendar month
+ MonthViewImpl monthView = new MonthViewImpl(mContext);
+
+ /* set view configuration parmeters */
+ HashMap<String, Integer> configureParams = new HashMap<String, Integer>();
+ configureParams.put(MonthView.VIEW_PARAMS_YEAR, mYear);
+ configureParams.put(MonthView.VIEW_PARAMS_MONTH, month);
+ monthView.setMonthParams(configureParams);
+
+ /* Customize view drawing parameters */
+ // The drawing parameters are calculated based on the actual container dimensions and the
+ // statically defined fraction components
+ HashMap<String, Integer> drawingParams = new HashMap<String, Integer>();
+ // padding in pixels ; applies to the left and right edges
+ drawingParams.put(MonthView.CONFIG_EDGE_PADDING, (int) (mMonthWidth * PADDING));
+ // add Month title header height
+ drawingParams.put(MonthView.CONFIG_HEADER_SIZE, (int) (mMonthHeight * MONTH_HEADER_HEIGHT));
+ // add Month label font size
+ drawingParams.put(MonthView.CONFIG_MONTH_LABEL_TEXT_SIZE,
+ (int) (mMonthHeight * MONTH_LABEL_FONT_SIZE));
+
+ // text size is chosen so that there isn't an overlap in the horizontal or vertical
+ // directions
+ double textSize = Math.min(mMonthHeight * MONTH_DAY_TEXT_SIZE,
+ mMonthWidth * MONTH_DAY_TEXT_SIZE);
+ // add text size for month days
+ drawingParams.put(MonthView.CONFIG_MONTH_DAY_TEXT_SIZE, (int) textSize);
+
+ // header label flag
+ drawingParams.put(MonthView.CONFIG_MONTH_HEADER_LABEL_FLAGS,
+ DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR |
+ DateUtils.FORMAT_NO_MONTH_DAY);
+
+ // add horizontal padding
+ drawingParams.put(MonthView.CONFIG_MONTH_ROW_HEIGHT,
+ (int) (mMonthHeight * ROW_HEIGHT));
+ drawingParams.put(MonthView.CONFIG_FILL_PARENT_CONTAINER, 1);
+ drawingParams.put(MonthView.CONFIG_HEADER_TITLE_COLOR, mMonthTitleColor);
+ drawingParams.put(MonthView.CONFIG_DAY_SELECTED_CIRCLE_COLOR, mMonthTitleColor);
+ drawingParams.put(MonthView.CONFIG_DAY_SELECTED_CIRCLE_ALPHA, 255);
+ drawingParams.put(MonthView.CONFIG_CURRENT_DAY_COLOR, mCurrentDayColor);
+
+ monthView.customizeViewParameters(drawingParams);
+
+ ViewGroup.LayoutParams viewParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ linearLayout.addView(monthView, viewParams);
+
+ return linearLayout;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ int action = event.getAction();
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mClickTimestamp = System.currentTimeMillis();
+ mClickX = event.getX();
+ mClickY = event.getY();
+ mClickedView = v;
+ // delay click acknowledgement to avoid view highlighting during scroll
+ mClickedView.postDelayed(mHighlightView, ViewConfiguration.getTapTimeout());
+ break;
+ case MotionEvent.ACTION_UP:
+ if (v == mClickedView) {
+ // avoid abrupt transitions in the UI by ensuring that the click animation
+ // persists for the minimum defined duration
+ long tapDuration = System.currentTimeMillis() - mClickTimestamp;
+ long delay = (tapDuration > mClickAnimDuration) ?
+ 0 : mClickAnimDuration - tapDuration;
+ v.postDelayed(mPerformClick, delay);
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ // clear view highlighting when the gesture becomes a scroll
+ if ((Math.abs(event.getX() - mClickX) > mTouchSlop) ||
+ (Math.abs(event.getY() - mClickY) > mTouchSlop)) {
+ clearClickedView(v);
+ }
+ break;
+ case MotionEvent.ACTION_SCROLL:
+ case MotionEvent.ACTION_CANCEL:
+ clearClickedView(v);
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Undoes click acknowledgement (view highlight)
+ */
+ private void clearClickedView(View v) {
+ v.removeCallbacks(mHighlightView);
+ synchronized (v) {
+ // restore the right bg color
+ if (v.getId() == mCurrentMonth) {
+ v.setBackgroundColor(mCurrentMonthBgColor);
+ } else {
+ v.setBackgroundColor(Color.TRANSPARENT);
+ }
+ }
+ mClickedView = null;
+ }
+
+ private final Runnable mHighlightView = new Runnable() {
+ @Override
+ public void run() {
+ mClickedView.setBackgroundColor(mMonthClickColor);
+ }
+ };
+
+ /**
+ * A runnable that completes the action mandated by a touch event. Used to delay the action
+ * consequence whilst the click animation is being performed.
+ */
+ private final Runnable mPerformClick = new Runnable() {
+ @Override
+ public void run() {
+ Time time = new Time(Time.getCurrentTimezone());
+ time.set(1, mClickedView.getId(), mYear); // set(day, month, year)
+ mController.sendEvent(mContext, EventType.GO_TO, time, time, -1,
+ CalendarController.ViewType.MONTH,
+ CalendarController.EXTRA_GOTO_BACK_TO_PREVIOUS, null, null );
+ }
+ };
+
+ /**
+ * A greedy LinearLayout that always intercepts the touch events from its children.
+ */
+ private static class GreedyLinearLayout extends LinearLayout {
+
+ public GreedyLinearLayout(Context context) {
+ super(context);
+ }
+
+ /**
+ * Always intercept the touch events
+ * @param ev touch event
+ * @return always true indicating that the touch events won't be propagated to the children
+ */
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return true;
+ }
+ }
+
+ /**
+ * Customized MonthView dictating how the days in a month are drawn onto the canvas
+ */
+ public static class MonthViewImpl extends MonthView {
+ public MonthViewImpl(Context context) {
+ super(context);
+ }
+
+ /**
+ * Tasked with drawing a day in the month onto the canvas
+ *
+ * @param canvas The canvas to draw on
+ * @param year The year of this month day
+ * @param month The month of this month day
+ * @param day The day number of this month day
+ * @param x The default x position to draw the day number
+ * @param y The default y position to draw the day number
+ * @param startX The left boundary of the day number rect
+ * @param stopX The right boundary of the day number rect
+ * @param startY The top boundary of the day number rect
+ * @param stopY The bottom boundary of the day number rect
+ */
+ @Override
+ public void drawMonthDay(Canvas canvas, int year, int month, int day,
+ int x, int y, int startX, int stopX, int startY, int stopY) {
+
+ if (mHasToday && mToday == day) {
+ int radius = mRowHeight / 2;
+ canvas.drawCircle(x , y - (mMiniDayNumberTextSize / 3), radius,
+ mSelectedCirclePaint);
+ mMonthNumPaint.setColor(mTodayNumberColor);
+ } else {
+ mMonthNumPaint.setColor(mDayTextColor);
+ }
+ canvas.drawText(String.format("%d", day), x, y, mMonthNumPaint);
+ }
+ }
+}
diff --git a/src/com/android/calendar/year/YearViewPagerFragment.java b/src/com/android/calendar/year/YearViewPagerFragment.java
new file mode 100644
index 00000000..494aac69
--- /dev/null
+++ b/src/com/android/calendar/year/YearViewPagerFragment.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.calendar.year;
+
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.os.Bundle;
+
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.GridView;
+import com.android.calendar.CalendarController;
+import com.android.calendar.CalendarController.EventType;
+import com.android.calendar.CalendarController.EventInfo;
+import com.android.calendar.R;
+import com.android.datetimepicker.date.MonthView;
+import com.android.datetimepicker.date.SimpleMonthView;
+
+import java.util.Calendar;
+import java.util.HashMap;
+
+/**
+ * Fragment encompassing a view pager to allow swiping between Years
+ */
+public class YearViewPagerFragment extends Fragment implements CalendarController.EventHandler {
+
+ private static final int EPOCH_TIME_YEAR_START = 1970;
+ private static final int EPOCH_TIME_YEAR_END = 2036;
+
+ private ViewPager mPager;
+ private YearViewPagerAdapter mPagerAdapter;
+ private int mCurrentYear;
+ private int mCurrentMonth; // the current month based on the current time
+ private int mCurrentPage;
+ private CalendarController mController;
+
+ public YearViewPagerFragment() {
+ this(System.currentTimeMillis());
+ }
+
+ public YearViewPagerFragment(long timeMillis) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(timeMillis);
+ mCurrentYear = calendar.get(Calendar.YEAR);
+ // check
+ if (mCurrentYear < EPOCH_TIME_YEAR_START || mCurrentYear > EPOCH_TIME_YEAR_END) {
+ mCurrentYear = EPOCH_TIME_YEAR_START;
+ }
+ mCurrentMonth = calendar.get(Calendar.MONTH);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ mController = CalendarController.getInstance(activity);
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.year_by_month, container, false);
+ mPager = (ViewPager) v.findViewById(R.id.pager);
+ mPagerAdapter = new YearViewPagerAdapter(getChildFragmentManager());
+ mPager.setAdapter(mPagerAdapter);
+
+ mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){
+ @Override
+ public void onPageSelected(int position) {
+ mCurrentPage = position;
+ updateTitle(EPOCH_TIME_YEAR_START + mCurrentPage);
+ }
+ });
+
+ return v;
+ }
+
+ /**
+ * Interacts with the Calendar controller to update the action bar title with the current
+ * year
+ *
+ * @param year year the title should be updated to
+ */
+ private void updateTitle(int year) {
+ Time start = new Time(Time.getCurrentTimezone());
+ start.set(1, 1, year);
+ long formatFlags = DateUtils.FORMAT_SHOW_YEAR;
+ mController.sendEvent(getActivity(), EventType.UPDATE_TITLE, start, start, null, -1,
+ CalendarController.ViewType.CURRENT, formatFlags, null, null);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ goToYear(mCurrentYear);
+ }
+
+ /**
+ * moves the pager to year specified by the input parameter
+ * @param year
+ */
+ public void goToYear(int year) {
+ if (mPager != null) {
+ mPager.setCurrentItem(year - EPOCH_TIME_YEAR_START);
+ }
+ }
+
+ @Override
+ public long getSupportedEventTypes() {
+ // support action bar navigation to the current time ("current time button")
+ return EventType.GO_TO;
+ }
+
+ @Override
+ public void handleEvent(EventInfo event) {
+ // handle "go to current time" action bar button click
+ if (event.eventType == EventType.GO_TO) {
+ goToYear(event.selectedTime.year);
+ }
+ }
+
+ @Override
+ public void eventsChanged() {
+ // nothing to do as this view doesn't depend on the underlying events database
+ }
+
+ /**
+ * Adapter class for the fragment view pager that displays the year views
+ *
+ */
+ public static class YearViewPagerAdapter extends FragmentPagerAdapter {
+
+ public YearViewPagerAdapter (FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int i) {
+ return YearViewFragment.newInstance(i);
+ }
+
+ // returns the count of years from 1970 - 2036 (inclusive)
+ @Override
+ public int getCount() {
+ return 67;
+ }
+ }
+
+ /**
+ * Fragment showing the entire year view
+ */
+ public static class YearViewFragment extends Fragment {
+ private GridView mGridView;
+ private YearViewAdapter mAdapter;
+ private int mYear;
+ private CalendarController mController;
+ private int mColumns;
+
+ static YearViewFragment newInstance(int yearOffset) {
+ YearViewFragment f = new YearViewFragment();
+
+ Bundle args = new Bundle();
+ args.putInt("year", EPOCH_TIME_YEAR_START + yearOffset);
+ f.setArguments(args);
+
+ return f;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ int orientation = getActivity().getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mColumns = 3; // the year view will be in a 4x3 configuration
+ } else {
+ mColumns = 4; // the year view will be in a 3x4 configuration
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mYear = getArguments() != null ? getArguments().getInt("year") :
+ EPOCH_TIME_YEAR_START;
+
+ mController = CalendarController.getInstance(getActivity());
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mGridView = new GridView(getActivity());
+ // set layout params ?
+ mGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
+ mGridView.setNumColumns(mColumns);
+
+ // we need to wait till the gridview is laid out
+ // the adapter drawing the year view depends on the dimensions of the grid view to
+ // figure out the layout and size of each of the months and its parameters
+ mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ // remove listener
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ mGridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ } else {
+ mGridView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ }
+
+ int gridWidth = mGridView.getWidth();
+ int gridHeight = mGridView.getHeight();
+
+ // prepare adapter and supply the dimensions it has to work with
+ mAdapter = new YearViewAdapter(getActivity(), mYear, mColumns);
+ mAdapter.setBounds(gridWidth, gridHeight);
+
+ mGridView.setAdapter(mAdapter);
+ }
+ });
+
+ return mGridView;
+ }
+ }
+}