/* * Copyright (C) 2006 The Android 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.androsz.electricsleepbeta.widget.calendar; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.List; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.text.format.Time; import android.util.Log; import android.util.SparseArray; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import com.androsz.electricsleepbeta.R; import com.androsz.electricsleepbeta.app.HistoryActivity; import com.androsz.electricsleepbeta.app.HistoryListFragment; import com.androsz.electricsleepbeta.app.HistoryMonthFragment; import com.androsz.electricsleepbeta.app.ReviewSleepActivity; import com.androsz.electricsleepbeta.db.SleepSession; public class MonthView extends View { private static final String TAG = MonthView.class.getSimpleName(); private static int BUSY_BITS_MARGIN = 4; private static int BUSY_BITS_WIDTH = 10; private static int EVENT_NUM_DAYS = 31; private static int MONTH_DAY_GAP = 1; private static int MONTH_DAY_TEXT_SIZE = 20; private static float mScale = 0; // Used for supporting different screen // densities /** * The selection modes are HIDDEN, PRESSED, SELECTED, and LONGPRESS. */ private static final int SELECTION_HIDDEN = 0; private static final int SELECTION_LONGPRESS = 3; private static final int SELECTION_PRESSED = 1; private static final int SELECTION_SELECTED = 2; private static int TEXT_TOP_MARGIN = 7; // densities private static int WEEK_GAP = 0; // An array of which days have events for quick reference private final boolean[] eventDay = new boolean[EVENT_NUM_DAYS]; // For drawing to an off-screen Canvas private Bitmap mBitmap; private final Rect mBitmapRect = new Rect(); private int mBorder; private Drawable mBoxLongPressed; private Drawable mBoxPressed; private Drawable mBoxSelected; private Canvas mCanvas; private int mCellHeight; private int mCellWidth; private DayOfMonthCursor mCursor; // Bitmap caches. // These improve performance by minimizing calls to NinePatchDrawable.draw() // for common // drawables for day backgrounds. // mDayBitmapCache is indexed by a unique integer constructed from the // width/height. private final SparseArray<Bitmap> mDayBitmapCache = new SparseArray<Bitmap>(4); // Index values into the mSessions array of longs private static final int SESSION_START_TIMESTAMP = 0; private static final int SESSION_END_TIMESTAMP = 1; private static final int SESSION_START_JULIAN = 2; private static final int SESSION_END_JULIAN = 3; private static final int SESSION_ROW_ID = 4; private List<Long[]> mSessions = new ArrayList<Long[]>(0); /** * The first Julian day of the current month. */ private int mFirstJulianDay; private GestureDetector mGestureDetector; private boolean mLaunchDayView; private int mMonthDayNumberColor; // Cached colors private int mMonthBackgroundColor; private int mMonthOtherMonthColor; private int mMonthOtherMonthDayNumberColor; private int mMonthSaturdayColor; private int mMonthWeekdayColor; private int mMonthSundayColor; private int mMonthTodayNumberColor; private int mEventOnColor; private int mEventOffColor; // This Time object is used to set the time for the other Month view. private final Time mOtherViewCalendar = new Time(); private final HistoryMonthFragment mParentActivity; // Pre-allocate and reuse private final Rect mRect = new Rect(); private boolean mRedrawScreen = true; private Resources mResources; private final Time mSavedTime = new Time(); // the time when we entered this // view private int mSelectionMode = SELECTION_HIDDEN; // These booleans disable features that were taken out of the spec. private final boolean mShowWeekNumbers = false; private int mStartDay; // This Time object is used for temporary calculations and is allocated // once to avoid extra garbage collection private final Time mTempTime = new Time(); private Time mToday; private Drawable mTodayBackground; private Time mViewCalendar; public MonthView(HistoryMonthFragment historyMonthActivity) { super(historyMonthActivity.getActivity()); if (mScale == 0) { mScale = getContext().getResources().getDisplayMetrics().density; if (mScale != 1) { WEEK_GAP *= mScale; MONTH_DAY_GAP *= mScale; MONTH_DAY_TEXT_SIZE *= mScale; TEXT_TOP_MARGIN *= mScale; BUSY_BITS_WIDTH *= mScale; BUSY_BITS_MARGIN *= mScale; } } mParentActivity = historyMonthActivity; init(); } /** * Clears the bitmap cache. Generally only needed when the screen size * changed. */ private void clearBitmapCache() { recycleAndClearBitmapCache(mDayBitmapCache); } private void doDraw(Canvas canvas) { final boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; final Paint p = new Paint(); final Rect r = mRect; final int columnDay1 = mCursor.getColumnOf(1); // Get the Julian day for the date at row 0, column 0. int day = mFirstJulianDay - columnDay1; int weekNum = 0; Calendar calendar = null; if (mShowWeekNumbers) { calendar = Calendar.getInstance(); final boolean noPrevMonth = (columnDay1 == 0); // Compute the week number for the first row. weekNum = getWeekOfYear(0, 0, noPrevMonth, calendar); } for (int row = 0; row < 6; row++) { for (int column = 0; column < 7; column++) { drawBox(day, weekNum, row, column, canvas, p, r, isLandscape); day += 1; } if (mShowWeekNumbers) { weekNum += 1; if (weekNum >= 53) { final boolean inCurrentMonth = (day - mFirstJulianDay < EVENT_NUM_DAYS); weekNum = getWeekOfYear(row + 1, 0, inCurrentMonth, calendar); } } } drawGrid(canvas, p); } /** * Draw a single box onto the canvas. * * @param day * The Julian day. * @param weekNum * The week number. * @param row * The row of the box (0-5). * @param column * The column of the box (0-6). * @param canvas * The canvas to draw on. * @param p * The paint used for drawing. * @param r * The rectangle used for each box. * @param isLandscape * Is the current orientation landscape. */ private void drawBox(int day, int weekNum, int row, int column, Canvas canvas, Paint p, Rect r, boolean isLandscape) { // Only draw the selection if we are in the press state or if we have // moved the cursor with key input. boolean drawSelection = false; if (mSelectionMode != SELECTION_HIDDEN) { drawSelection = mCursor.isSelected(row, column); } final boolean withinCurrentMonth = mCursor.isWithinCurrentMonth(row, column); boolean isToday = false; final int dayOfBox = mCursor.getDayAt(row, column); if (dayOfBox == mToday.monthDay && mCursor.getYear() == mToday.year && mCursor.getMonth() == mToday.month) { isToday = true; } final int y = WEEK_GAP + row * (WEEK_GAP + mCellHeight); final int x = mBorder + column * (MONTH_DAY_GAP + mCellWidth); r.left = x; r.top = y; r.right = x + mCellWidth; r.bottom = y + mCellHeight; // Adjust the left column, right column, and bottom row to leave // no border. if (column == 0) { r.left = -1; } else if (column == 6) { r.right += mBorder + 2; } if (row == 5) { r.bottom = getMeasuredHeight(); } // Draw the cell contents (excluding monthDay number) if (!withinCurrentMonth) { // Adjust cell boundaries to compensate for the different border // style. r.top--; if (column != 0) { r.left--; } p.setStyle(Style.FILL); p.setColor(mMonthOtherMonthColor); canvas.drawRect(r, p); } else if (drawSelection) { if (mSelectionMode == SELECTION_SELECTED) { mBoxSelected.setBounds(r); mBoxSelected.draw(canvas); } else if (mSelectionMode == SELECTION_PRESSED) { mBoxPressed.setBounds(r); mBoxPressed.draw(canvas); } else { mBoxLongPressed.setBounds(r); mBoxLongPressed.draw(canvas); } // Places events for that day drawEvents(day, canvas, r, p, false /* draw bb background */); } else { // Today gets a different background if (isToday) { // We could cache this for a little bit more performance, but // it's not on the // performance radar... final Drawable background = mTodayBackground; background.setBounds(r); background.draw(canvas); } else { // Background for dates that are within the month. p.setStyle(Style.FILL); p.setColor(mMonthBackgroundColor); canvas.drawRect(r, p); } // Places events for that day drawEvents(day, canvas, r, p, !isToday /* draw bb background */); } // Draw the monthDay number p.setStyle(Paint.Style.FILL); p.setAntiAlias(true); p.setTypeface(null); p.setTextSize(MONTH_DAY_TEXT_SIZE); if (!withinCurrentMonth) { p.setColor(mMonthOtherMonthDayNumberColor); } else { if (isToday && !drawSelection) { p.setColor(mMonthTodayNumberColor); } else if (Utils.isSunday(column, mStartDay)) { p.setColor(mMonthSundayColor); } else if (Utils.isSaturday(column, mStartDay)) { p.setColor(mMonthSaturdayColor); } else { p.setColor(mMonthWeekdayColor); } // bolds the day if there's an event that day p.setFakeBoldText(eventDay[day - mFirstJulianDay]); } /* * Drawing of day number is done hereeasy to find tags draw number draw * day */ p.setTextAlign(Paint.Align.CENTER); // center of text final int textX = r.left + (r.right - BUSY_BITS_MARGIN - BUSY_BITS_WIDTH - r.left) / 2; final int textY = (int) (r.top + p.getTextSize() + TEXT_TOP_MARGIN); // bottom // of // text canvas.drawText(String.valueOf(mCursor.getDayAt(row, column)), textX, textY, p); } // /Create and draw the event busybits for this day private void drawEvents(int date, Canvas canvas, Rect rect, Paint p, boolean drawBg) { // The top of the busybits section lines up with the top of the day // number Paint paint = new Paint(); paint.setColor(mEventOffColor); for (Long[] session : mSessions) { if (date == session[SESSION_START_JULIAN]) { paint.setColor(mEventOnColor); break; } } final int height = Math.abs(rect.bottom - rect.top); final int width = Math.abs(rect.right - rect.left); Log.d(TAG, "width = " + width + " height = " + height); int rx; if (width < height) { rx = (int) (width / 4); } else { rx = (int) (height / 4); } // TODO the following places the indicator in the bottom center of the month marking but //this does not work well if there is only enough space for the numbering. //int cy = (int) (height / 1.4)); //int cx = (int) (rect.left + (width / 2)); int cy = (int) (rect.bottom - rx - (rx / 4)); int cx = (int) (rect.right - rx - (rx / 4)); canvas.drawCircle(cx, cy, rx, paint); } /** * Draw the grid lines for the calendar * * @param canvas * The canvas to draw on. * @param p * The paint used for drawing. */ private void drawGrid(Canvas canvas, Paint p) { p.setColor(Color.WHITE); p.setAntiAlias(false); final int width = getMeasuredWidth(); final int height = getMeasuredHeight(); for (int row = 0; row < 6; row++) { final int y = WEEK_GAP + row * (WEEK_GAP + mCellHeight) - 1; canvas.drawLine(0, y, width, y, p); } for (int column = 1; column < 7; column++) { final int x = mBorder + column * (MONTH_DAY_GAP + mCellWidth) - 1; canvas.drawLine(x, WEEK_GAP, x, height, p); } } private void drawingCalc(int width, int height) { mCellHeight = (height - (6 * WEEK_GAP)) / 6; // TODO // mEventGeometry // .setHourHeight((mCellHeight - BUSY_BITS_MARGIN * 2 - TEXT_TOP_MARGIN) // / 24.0f); mCellWidth = (width - (6 * MONTH_DAY_GAP)) / 7; mBorder = (width - 6 * (mCellWidth + MONTH_DAY_GAP) - mCellWidth) / 2; if (((mBitmap == null) || mBitmap.isRecycled() || (mBitmap.getHeight() != height) || (mBitmap .getWidth() != width)) && (width > 0) && (height > 0)) { if (mBitmap != null) { mBitmap.recycle(); } mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); } mBitmapRect.top = 0; mBitmapRect.bottom = height; mBitmapRect.left = 0; mBitmapRect.right = width; } public void forceReloadEvents(final List<Long[]> sessions) { new Thread(new Runnable() { @Override public void run() { // android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LOWEST); //final Time monthStart = mTempTime; //monthStart.set(mViewCalendar); //monthStart.monthDay = 1; //monthStart.hour = 0; //monthStart.minute = 0; //monthStart.second = 0; //final long startOfMonthMillis = monthStart.normalize(true); mSessions = new ArrayList<Long[]>(sessions);//new ArrayList<Long[]>(sessions); // Clear out event days Arrays.fill(eventDay, false); // Compute the new set of days with events for (final Long[] session : mSessions) { long startDay = session[SESSION_START_JULIAN] - mFirstJulianDay; long endDay = session[SESSION_END_JULIAN] - mFirstJulianDay + 1; if (startDay < EVENT_NUM_DAYS || endDay >= 0) { if (startDay < 0) { startDay = 0; } if (startDay > EVENT_NUM_DAYS) { startDay = EVENT_NUM_DAYS; } if (endDay < 0) { endDay = 0; } if (endDay > EVENT_NUM_DAYS) { endDay = EVENT_NUM_DAYS; } for (int j = (int) startDay; j < endDay; j++) { eventDay[j] = true; } } } mRedrawScreen = true; postInvalidate(); } }).start(); } private long getSelectedMillisFor(int x, int y) { final int row = (y - WEEK_GAP) / (WEEK_GAP + mCellHeight); int column = (x - mBorder) / (MONTH_DAY_GAP + mCellWidth); if (column > 6) { column = 6; } final DayOfMonthCursor c = mCursor; final Time time = mTempTime; time.set(mViewCalendar); time.set(0, 0, 0, time.monthDay, time.month, time.year); // Compute the day number from the row and column. If the row and // column are in a different month from the current one, then the // monthDay might be negative or it might be greater than the number // of days in this month, but that is okay because the normalize() // method will adjust the month (and year) if necessary. time.monthDay = 7 * row + column - c.getOffset() + 1; return time.normalize(true); } public long getSelectedTimeInMillis() { final Time time = mTempTime; time.set(mViewCalendar); time.month += mCursor.getSelectedMonthOffset(); time.monthDay = mCursor.getSelectedDayOfMonth(); // Restore the saved hour:minute:second offset from when we entered // this view. time.second = mSavedTime.second; time.minute = mSavedTime.minute; time.hour = mSavedTime.hour; return time.normalize(true); } public int getSelectionMode() { return mSelectionMode; } public Time getTime() { return mViewCalendar; } private int getWeekOfYear(int row, int column, boolean isWithinCurrentMonth, Calendar calendar) { calendar.set(Calendar.DAY_OF_MONTH, mCursor.getDayAt(row, column)); if (isWithinCurrentMonth) { calendar.set(Calendar.MONTH, mCursor.getMonth()); calendar.set(Calendar.YEAR, mCursor.getYear()); } else { int month = mCursor.getMonth(); int year = mCursor.getYear(); if (row < 2) { // Previous month if (month == 0) { year--; month = 11; } else { month--; } } else { // Next month if (month == 11) { year++; month = 0; } else { month++; } } calendar.set(Calendar.MONTH, month); calendar.set(Calendar.YEAR, year); } return calendar.get(Calendar.WEEK_OF_YEAR); } private void init() { setFocusable(true); setClickable(true); mViewCalendar = new Time(); final long now = System.currentTimeMillis(); mViewCalendar.set(now); mViewCalendar.monthDay = 1; final long millis = mViewCalendar.normalize(true /* ignore DST */); mFirstJulianDay = Time.getJulianDay(millis, mViewCalendar.gmtoff); mStartDay = Utils.getFirstDayOfWeek(); mViewCalendar.set(now); mCursor = new DayOfMonthCursor(mViewCalendar.year, mViewCalendar.month, mViewCalendar.monthDay, mParentActivity.getStartDay()); mToday = new Time(); mToday.set(System.currentTimeMillis()); mResources = mParentActivity.getResources(); mBoxSelected = mResources.getDrawable(R.drawable.month_view_selected); mBoxPressed = mResources.getDrawable(R.drawable.month_view_pressed); mBoxLongPressed = mResources.getDrawable(R.drawable.month_view_longpress); mTodayBackground = mResources.getDrawable(R.drawable.month_view_today_background); // Cache color lookups final Resources res = getResources(); mMonthBackgroundColor = res.getColor(R.color.faded_grey); mMonthOtherMonthColor = res.getColor(R.color.background_dark); mMonthOtherMonthDayNumberColor = res.getColor(R.color.faded_grey); mMonthDayNumberColor = res.getColor(R.color.text_light); mMonthTodayNumberColor = res.getColor(R.color.primary1_transparent); mMonthSaturdayColor = res.getColor(R.color.text_light); mMonthWeekdayColor = res.getColor(R.color.text_light); mMonthSundayColor = res.getColor(R.color.text_light); mEventOnColor = res.getColor(R.color.primary_dark); mEventOffColor = res.getColor(R.color.less_faded_grey); mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { // Launch the Day/Agenda view when the finger lifts up, // unless the finger moves before lifting up (onFling or // onScroll). mLaunchDayView = true; return true; } @Override public void onLongPress(MotionEvent e) { // If mLaunchDayView is true, then we haven't done any // scrolling // after touching the screen, so allow long-press to // proceed // with popping up the context menu. if (mLaunchDayView) { mLaunchDayView = false; mSelectionMode = SELECTION_LONGPRESS; mRedrawScreen = true; invalidate(); performLongClick(); } } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // If the user moves his finger after touching, then do // not // launch the Day view when he lifts his finger. Also, // turn // off the selection. mLaunchDayView = false; if (mSelectionMode != SELECTION_HIDDEN) { mSelectionMode = SELECTION_HIDDEN; mRedrawScreen = true; invalidate(); } return true; } @Override public void onShowPress(MotionEvent e) { // Highlight the selected day. setSelectedCell(e); mSelectionMode = SELECTION_PRESSED; mRedrawScreen = true; invalidate(); } @Override public boolean onSingleTapUp(MotionEvent e) { if (mLaunchDayView) { setSelectedCell(e); mSelectionMode = SELECTION_SELECTED; mRedrawScreen = true; invalidate(); mLaunchDayView = false; final int x = (int) e.getX(); final int y = (int) e.getY(); final long millis = getSelectedMillisFor(x, y); Log.d(TAG, "Possibly reviewing sleep at: " + millis); reviewSleepIfNecessary(millis); } return true; } public void setSelectedCell(MotionEvent e) { final int x = (int) e.getX(); final int y = (int) e.getY(); int row = (y - WEEK_GAP) / (WEEK_GAP + mCellHeight); int col = (x - mBorder) / (MONTH_DAY_GAP + mCellWidth); if (row > 5) { row = 5; } if (col > 6) { col = 6; } // Highlight the selected day. mCursor.setSelectedRowColumn(row, col); } }); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); // No need to hang onto the bitmaps... clearBitmapCache(); if (mBitmap != null) { mBitmap.recycle(); } } @Override protected void onDraw(Canvas canvas) { if (mRedrawScreen) { if (mCanvas == null) { drawingCalc(getWidth(), getHeight()); } // If we are zero-sized, the canvas will remain null so check again if (mCanvas != null) { // Clear the background final Canvas bitmapCanvas = mCanvas; bitmapCanvas.drawColor(0, PorterDuff.Mode.CLEAR); doDraw(bitmapCanvas); mRedrawScreen = false; } } // If we are zero-sized, the bitmap will be null so guard against this if (mBitmap != null) { canvas.drawBitmap(mBitmap, mBitmapRect, mBitmapRect, null); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (mSelectionMode == SELECTION_HIDDEN) { if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { // Display the selection box but don't move or select it // on this key press. mSelectionMode = SELECTION_SELECTED; mRedrawScreen = true; invalidate(); return true; } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { // Display the selection box but don't select it // on this key press. mSelectionMode = SELECTION_PRESSED; mRedrawScreen = true; invalidate(); return true; } } mSelectionMode = SELECTION_SELECTED; boolean redraw = false; Time other = null; switch (keyCode) { case KeyEvent.KEYCODE_ENTER: final long millis = getSelectedTimeInMillis(); reviewSleepIfNecessary(millis); return true; case KeyEvent.KEYCODE_DPAD_UP: if (mCursor.up()) { other = mOtherViewCalendar; other.set(mViewCalendar); other.month -= 1; other.monthDay = mCursor.getSelectedDayOfMonth(); // restore the calendar cursor for the animation mCursor.down(); } redraw = true; break; case KeyEvent.KEYCODE_DPAD_DOWN: if (mCursor.down()) { other = mOtherViewCalendar; other.set(mViewCalendar); other.month += 1; other.monthDay = mCursor.getSelectedDayOfMonth(); // restore the calendar cursor for the animation mCursor.up(); } redraw = true; break; case KeyEvent.KEYCODE_DPAD_LEFT: if (mCursor.left()) { other = mOtherViewCalendar; other.set(mViewCalendar); other.month -= 1; other.monthDay = mCursor.getSelectedDayOfMonth(); // restore the calendar cursor for the animation mCursor.right(); } redraw = true; break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (mCursor.right()) { other = mOtherViewCalendar; other.set(mViewCalendar); other.month += 1; other.monthDay = mCursor.getSelectedDayOfMonth(); // restore the calendar cursor for the animation mCursor.left(); } redraw = true; break; } if (other != null) { other.normalize(true /* ignore DST */); // TODO // mNavigator.goTo(other, true); } else if (redraw) { mRedrawScreen = true; invalidate(); } return redraw; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { final long duration = event.getEventTime() - event.getDownTime(); switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: if (mSelectionMode == SELECTION_HIDDEN) { // Don't do anything unless the selection is visible. break; } if (mSelectionMode == SELECTION_PRESSED) { // This was the first press when there was nothing selected. // Change the selection from the "pressed" state to the // the "selected" state. We treat short-press and // long-press the same here because nothing was selected. mSelectionMode = SELECTION_SELECTED; mRedrawScreen = true; invalidate(); break; } // Check the duration to determine if this was a short press if (duration < ViewConfiguration.getLongPressTimeout()) { final long millis = getSelectedTimeInMillis(); reviewSleepIfNecessary(millis); } else { mSelectionMode = SELECTION_LONGPRESS; mRedrawScreen = true; invalidate(); performLongClick(); } } return super.onKeyUp(keyCode, event); } @Override protected void onSizeChanged(int width, int height, int oldw, int oldh) { drawingCalc(width, height); // If the size changed, then we should rebuild the bitmaps... clearBitmapCache(); } @Override public boolean onTouchEvent(MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) { return true; } return super.onTouchEvent(event); } private void recycleAndClearBitmapCache(SparseArray<Bitmap> bitmapCache) { final int size = bitmapCache.size(); for (int i = 0; i < size; i++) { bitmapCache.valueAt(i).recycle(); } bitmapCache.clear(); } /** * Method determines what activity to load when user presses a date square in the calendar view. * Either loads a list view of a collection of nights (naps) OR a single night to review. */ private void reviewSleepIfNecessary(final long millis) { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { //final ArrayList<Long[]> applicableEvents = new ArrayList<Long[]>(); final long ONE_DAY_IN_MS = 1000 * 60 * 60 * 24; final int julianDay = Time.getJulianDay(millis, new Time().gmtoff); List<Long> applicableRowIds = new ArrayList<Long>(); for (final Long[] session : mSessions) { if (julianDay == session[SESSION_START_JULIAN]) { Log.d(TAG, "Adding session: " + session[SESSION_ROW_ID] + " to date: " + julianDay); applicableRowIds.add(session[SESSION_ROW_ID]); } /* * final long startTime = session[0] - thismillis; final * long endTime = session[1] - thismillis; if ((endTime > 0) * && ((startTime <= ONE_DAY_IN_MS && startTime > 0) || * startTime < 0)) { * * applicableEvents.add(session); } */ } if (applicableRowIds.size() == 1) { // Only one session so load night review. final Intent reviewSleepIntent = new Intent(getContext(), ReviewSleepActivity.class); final Uri data = Uri.withAppendedPath(SleepSession.CONTENT_URI, String.valueOf(applicableRowIds.get(0))); reviewSleepIntent.setData(data); getContext().startActivity(reviewSleepIntent); } else if (applicableRowIds.size() > 1) { // TODO this probably needs to be smarter in how it attempts to discover sleep // for a given night. Its quite possible that the night of sleep for the user on // say a Friday began at say Saturday morning at 3am. We need to handle this // situation. getContext().startActivity( new Intent(getContext(), HistoryActivity.class).putExtra( HistoryListFragment.EXTRA_JULIAN_DAY, julianDay)); } return null; } }.execute(); } public void setTime(Time time) { mViewCalendar.set(time); mViewCalendar.monthDay = 1; final long millis = mViewCalendar.normalize(true /* ignore DST */); mFirstJulianDay = Time.getJulianDay(millis, mViewCalendar.gmtoff); mViewCalendar.set(time); mCursor = new DayOfMonthCursor(time.year, time.month, time.monthDay, mCursor.getWeekStartDay()); this.mSelectionMode = MonthView.SELECTION_HIDDEN; mRedrawScreen = true; invalidate(); } public void setSelectedTime(Time time) { // Save the selected time so that we can restore it later when we switch // views. mSavedTime.set(time); mViewCalendar.set(time); mViewCalendar.monthDay = 1; final long millis = mViewCalendar.normalize(true /* ignore DST */); mFirstJulianDay = Time.getJulianDay(millis, mViewCalendar.gmtoff); mViewCalendar.set(time); mCursor = new DayOfMonthCursor(time.year, time.month, time.monthDay, mCursor.getWeekStartDay()); mRedrawScreen = true; invalidate(); } public void setSelectionMode(int selectionMode) { mSelectionMode = selectionMode; } @Override public String toString() { return Utils.formatMonthYear(getContext(), mViewCalendar); } }