CalendarViewpublic class CalendarView extends android.view.View implements View.OnCreateContextMenuListener, View.OnClickListenerThis is the base class for a set of classes that implement views (day view
and week view to start with) that share some common code. |
Fields Summary |
---|
private boolean | mOnFlingCalled | protected CalendarApplication | mCalendarApp | protected CalendarActivity | mParentActivity | private static final String[] | CALENDARS_PROJECTION | private static final int | CALENDARS_INDEX_ACCESS_LEVEL | private static final String | CALENDARS_WHERE | private static final String[] | ATTENDEES_PROJECTION | private static final int | ATTENDEES_INDEX_RELATIONSHIP | private static final String | ATTENDEES_WHERE | private static final float | SMALL_ROUND_RADIUS | private static final int | FROM_NONE | private static final int | FROM_ABOVE | private static final int | FROM_BELOW | private static final int | FROM_LEFT | private static final int | FROM_RIGHT | private static final int | HORIZONTAL_SCROLL_THRESHOLD | private ContinueScroll | mContinueScroll | android.text.format.Time | mBaseDate | private android.graphics.Typeface | mBold | private int | mFirstJulianDay | private int | mLastJulianDay | private int | mMonthLength | private int | mFirstDate | private int[] | mEarliestStartHour | private boolean[] | mHasAllDayEvent | private String | mDetailedView | private long | mLastReloadMillisThis variable helps to avoid unnecessarily reloading events by keeping
track of the start millis parameter used for the most recent loading
of events. If the next reload matches this, then the events are not
reloaded. To force a reload, set this to zero (this is set to zero
in the method clearCachedEvents()). | private ArrayList | mEvents | private int | mSelectionDay | private int | mSelectionHour | boolean | mSelectionAllDay | private int | mCellWidth | private boolean | mLaunchNewView | private android.graphics.Rect | mRect | private android.graphics.RectF | mRectF | private android.graphics.Rect | mSrcRect | private android.graphics.Rect | mDestRect | private android.graphics.Paint | mPaint | private android.graphics.Paint | mPaintBorder | private android.graphics.Paint | mEventTextPaint | private android.graphics.Paint | mSelectionPaint | private android.graphics.Path | mPath | protected boolean | mDrawTextInEventRect | private int | mStartDay | private android.widget.PopupWindow | mPopup | private android.view.View | mPopupView | private static final int | POPUP_DISMISS_DELAY | private DismissPopup | mDismissPopup | private android.graphics.Bitmap | mBitmap | private android.graphics.Canvas | mCanvas | private boolean | mRedrawScreen | private boolean | mRemeasure | private final EventLoader | mEventLoader | protected final EventGeometry | mEventGeometry | private static final int | DAY_GAP | private static final int | HOUR_GAP | private static final int | SINGLE_ALLDAY_HEIGHT | private static final int | MAX_ALLDAY_HEIGHT | private static final int | ALLDAY_TOP_MARGIN | private static final int | MAX_ALLDAY_EVENT_HEIGHT | private static final int | ALL_DAY_TEXT_TOP_MARGIN | private static final int | NORMAL_TEXT_TOP_MARGIN | private static final int | HOURS_LEFT_MARGIN | private static final int | HOURS_RIGHT_MARGIN | private static final int | HOURS_MARGIN | static final int | MINUTES_PER_HOUR | static final int | MINUTES_PER_DAY | static final int | MILLIS_PER_MINUTE | static final int | MILLIS_PER_HOUR | static final int | MILLIS_PER_DAY | private static final int | NORMAL_FONT_SIZE | private static final int | EVENT_TEXT_FONT_SIZE | private static final int | HOURS_FONT_SIZE | private static final int | AMPM_FONT_SIZE | private static final int | MIN_CELL_WIDTH_FOR_TEXT | private static final int | MAX_EVENT_TEXT_LEN | private static final float | MIN_EVENT_HEIGHT | private static int | mSelectionColor | private static int | mPressedColor | private static int | mSelectedEventTextColor | private static int | mEventTextColor | private int | mViewStartX | private int | mViewStartY | private int | mMaxViewStartY | private int | mBitmapHeight | private int | mViewHeight | private int | mViewWidth | private int | mGridAreaHeight | private int | mCellHeight | private int | mScrollStartY | private int | mPreviousDirection | private int | mPreviousDistanceX | private int | mHoursTextHeight | private int | mEventTextAscent | private int | mEventTextHeight | private int | mAllDayHeight | private int | mBannerPlusMargin | private int | mMaxAllDayEvents | protected int | mNumDays | private int | mNumHours | private int | mHoursWidth | private int | mDateStrWidth | private int | mFirstCell | private int | mFirstHour | private int | mFirstHourOffset | private String[] | mHourStrs | private String[] | mDayStrs | private String[] | mDayStrs2Letter | private boolean | mIs24HourFormat | private float[] | mCharWidths | private ArrayList | mSelectedEvents | private boolean | mComputeSelectedEvents | private Event | mSelectedEvent | private Event | mPrevSelectedEvent | private android.graphics.Rect | mPrevBox | protected final android.content.res.Resources | mResources | private String | mAmString | private String | mPmString | private DeleteEventHelper | mDeleteEventHelper | private ContextMenuHandler | mContextMenuHandler | private static final int | TOUCH_MODE_INITIAL_STATEThe initial state of the touch mode when we enter this view. | private static final int | TOUCH_MODE_DOWNIndicates we just received the touch event and we are waiting to see if
it is a tap or a scroll gesture. | private static final int | TOUCH_MODE_VSCROLLIndicates the touch gesture is a vertical scroll | private static final int | TOUCH_MODE_HSCROLLIndicates the touch gesture is a horizontal scroll | private int | mTouchMode | private static final int | SELECTION_HIDDENThe selection modes are HIDDEN, PRESSED, SELECTED, and LONGPRESS. | private static final int | SELECTION_PRESSED | private static final int | SELECTION_SELECTED | private static final int | SELECTION_LONGPRESS | private int | mSelectionMode | private boolean | mScrolling | private String | mDateRange | private android.widget.TextView | mTitleTextView | private Runnable | mCancelCallback |
Constructors Summary |
---|
public CalendarView(CalendarActivity activity)
super(activity);
mResources = activity.getResources();
mEventLoader = activity.mEventLoader;
mEventGeometry = new EventGeometry();
mEventGeometry.setMinEventHeight(MIN_EVENT_HEIGHT);
mEventGeometry.setHourGap(HOUR_GAP);
mParentActivity = activity;
mCalendarApp = (CalendarApplication) mParentActivity.getApplication();
mDeleteEventHelper = new DeleteEventHelper(activity, false /* don't exit when done */);
init(activity);
|
Methods Summary |
---|
private void | adjustHourSelection()
if (mSelectionHour < 0) {
mSelectionHour = 0;
if (mMaxAllDayEvents > 0) {
mPrevSelectedEvent = null;
mSelectionAllDay = true;
}
}
if (mSelectionHour > 23) {
mSelectionHour = 23;
}
// If the selected hour is at least 2 time slots from the top and
// bottom of the screen, then don't scroll the view.
if (mSelectionHour < mFirstHour + 1) {
// If there are all-days events for the selected day but there
// are no more normal events earlier in the day, then jump to
// the all-day event area.
// Exception 1: allow the user to scroll to 8am with the trackball
// before jumping to the all-day event area.
// Exception 2: if 12am is on screen, then allow the user to select
// 12am before going up to the all-day event area.
int daynum = mSelectionDay - mFirstJulianDay;
if (mMaxAllDayEvents > 0 && mEarliestStartHour[daynum] > mSelectionHour
&& mFirstHour > 0 && mFirstHour < 8) {
mPrevSelectedEvent = null;
mSelectionAllDay = true;
mSelectionHour = mFirstHour + 1;
return;
}
if (mFirstHour > 0) {
mFirstHour -= 1;
mViewStartY -= (mCellHeight + HOUR_GAP);
if (mViewStartY < 0) {
mViewStartY = 0;
}
return;
}
}
if (mSelectionHour > mFirstHour + mNumHours - 3) {
if (mFirstHour < 24 - mNumHours) {
mFirstHour += 1;
mViewStartY += (mCellHeight + HOUR_GAP);
if (mViewStartY > mBitmapHeight - mGridAreaHeight) {
mViewStartY = mBitmapHeight - mGridAreaHeight;
}
return;
} else if (mFirstHour == 24 - mNumHours && mFirstHourOffset > 0) {
mViewStartY = mBitmapHeight - mGridAreaHeight;
}
}
| public void | cleanup()Cleanup the pop-up.
// Protect against null-pointer exceptions
if (mPopup != null) {
mPopup.dismiss();
}
Handler handler = getHandler();
if (handler != null) {
handler.removeCallbacks(mDismissPopup);
}
// Turn off redraw
mRemeasure = false;
mRedrawScreen = false;
| void | clearCachedEvents()
mLastReloadMillis = 0;
| private void | computeAllDayNeighbors()
int len = mSelectedEvents.size();
if (len == 0 || mSelectedEvent != null) {
return;
}
// First, clear all the links
for (int ii = 0; ii < len; ii++) {
Event ev = mSelectedEvents.get(ii);
ev.nextUp = null;
ev.nextDown = null;
ev.nextLeft = null;
ev.nextRight = null;
}
// For each event in the selected event list "mSelectedEvents", find
// its neighbors in the up and down directions. This could be done
// more efficiently by sorting on the Event.getColumn() field, but
// the list is expected to be very small.
// Find the event in the same row as the previously selected all-day
// event, if any.
int startPosition = -1;
if (mPrevSelectedEvent != null && mPrevSelectedEvent.allDay) {
startPosition = mPrevSelectedEvent.getColumn();
}
int maxPosition = -1;
Event startEvent = null;
Event maxPositionEvent = null;
for (int ii = 0; ii < len; ii++) {
Event ev = mSelectedEvents.get(ii);
int position = ev.getColumn();
if (position == startPosition) {
startEvent = ev;
} else if (position > maxPosition) {
maxPositionEvent = ev;
maxPosition = position;
}
for (int jj = 0; jj < len; jj++) {
if (jj == ii) {
continue;
}
Event neighbor = mSelectedEvents.get(jj);
int neighborPosition = neighbor.getColumn();
if (neighborPosition == position - 1) {
ev.nextUp = neighbor;
} else if (neighborPosition == position + 1) {
ev.nextDown = neighbor;
}
}
}
if (startEvent != null) {
mSelectedEvent = startEvent;
} else {
mSelectedEvent = maxPositionEvent;
}
| private void | computeFirstHour()Recomputes the first full hour that is visible on screen after the
screen is scrolled.
// Compute the first full hour that is visible on screen
mFirstHour = (mViewStartY + mCellHeight + HOUR_GAP - 1) / (mCellHeight + HOUR_GAP);
mFirstHourOffset = mFirstHour * (mCellHeight + HOUR_GAP) - mViewStartY;
| private int | computeMaxStringWidth(int currentMax, java.lang.String[] strings, android.graphics.Paint p)
float maxWidthF = 0.0f;
int len = strings.length;
for (int i = 0; i < len; i++) {
float width = p.measureText(strings[i]);
maxWidthF = Math.max(width, maxWidthF);
}
int maxWidth = (int) (maxWidthF + 0.5);
if (maxWidth < currentMax) {
maxWidth = currentMax;
}
return maxWidth;
| private void | computeNeighbors()
int len = mSelectedEvents.size();
if (len == 0 || mSelectedEvent != null) {
return;
}
// First, clear all the links
for (int ii = 0; ii < len; ii++) {
Event ev = mSelectedEvents.get(ii);
ev.nextUp = null;
ev.nextDown = null;
ev.nextLeft = null;
ev.nextRight = null;
}
Event startEvent = mSelectedEvents.get(0);
int startEventDistance1 = 100000; // any large number
int startEventDistance2 = 100000; // any large number
int prevLocation = FROM_NONE;
int prevTop;
int prevBottom;
int prevLeft;
int prevRight;
int prevCenter = 0;
Rect box = getCurrentSelectionPosition();
if (mPrevSelectedEvent != null) {
prevTop = (int) mPrevSelectedEvent.top;
prevBottom = (int) mPrevSelectedEvent.bottom;
prevLeft = (int) mPrevSelectedEvent.left;
prevRight = (int) mPrevSelectedEvent.right;
// Check if the previously selected event intersects the previous
// selection box. (The previously selected event may be from a
// much older selection box.)
if (prevTop >= mPrevBox.bottom || prevBottom <= mPrevBox.top
|| prevRight <= mPrevBox.left || prevLeft >= mPrevBox.right) {
mPrevSelectedEvent = null;
prevTop = mPrevBox.top;
prevBottom = mPrevBox.bottom;
prevLeft = mPrevBox.left;
prevRight = mPrevBox.right;
} else {
// Clip the top and bottom to the previous selection box.
if (prevTop < mPrevBox.top) {
prevTop = mPrevBox.top;
}
if (prevBottom > mPrevBox.bottom) {
prevBottom = mPrevBox.bottom;
}
}
} else {
// Just use the previously drawn selection box
prevTop = mPrevBox.top;
prevBottom = mPrevBox.bottom;
prevLeft = mPrevBox.left;
prevRight = mPrevBox.right;
}
// Figure out where we came from and compute the center of that area.
if (prevLeft >= box.right) {
// The previously selected event was to the right of us.
prevLocation = FROM_RIGHT;
prevCenter = (prevTop + prevBottom) / 2;
} else if (prevRight <= box.left) {
// The previously selected event was to the left of us.
prevLocation = FROM_LEFT;
prevCenter = (prevTop + prevBottom) / 2;
} else if (prevBottom <= box.top) {
// The previously selected event was above us.
prevLocation = FROM_ABOVE;
prevCenter = (prevLeft + prevRight) / 2;
} else if (prevTop >= box.bottom) {
// The previously selected event was below us.
prevLocation = FROM_BELOW;
prevCenter = (prevLeft + prevRight) / 2;
}
// For each event in the selected event list "mSelectedEvents", search
// all the other events in that list for the nearest neighbor in 4
// directions.
for (int ii = 0; ii < len; ii++) {
Event ev = mSelectedEvents.get(ii);
int startTime = ev.startTime;
int endTime = ev.endTime;
int left = (int) ev.left;
int right = (int) ev.right;
int top = (int) ev.top;
if (top < box.top) {
top = box.top;
}
int bottom = (int) ev.bottom;
if (bottom > box.bottom) {
bottom = box.bottom;
}
if (false) {
int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
| DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
if (DateFormat.is24HourFormat(mContext)) {
flags |= DateUtils.FORMAT_24HOUR;
}
String timeRange = DateUtils.formatDateRange(mParentActivity,
ev.startMillis, ev.endMillis, flags);
Log.i("Cal", "left: " + left + " right: " + right + " top: " + top
+ " bottom: " + bottom + " ev: " + timeRange + " " + ev.title);
}
int upDistanceMin = 10000; // any large number
int downDistanceMin = 10000; // any large number
int leftDistanceMin = 10000; // any large number
int rightDistanceMin = 10000; // any large number
Event upEvent = null;
Event downEvent = null;
Event leftEvent = null;
Event rightEvent = null;
// Pick the starting event closest to the previously selected event,
// if any. distance1 takes precedence over distance2.
int distance1 = 0;
int distance2 = 0;
if (prevLocation == FROM_ABOVE) {
if (left >= prevCenter) {
distance1 = left - prevCenter;
} else if (right <= prevCenter) {
distance1 = prevCenter - right;
}
distance2 = top - prevBottom;
} else if (prevLocation == FROM_BELOW) {
if (left >= prevCenter) {
distance1 = left - prevCenter;
} else if (right <= prevCenter) {
distance1 = prevCenter - right;
}
distance2 = prevTop - bottom;
} else if (prevLocation == FROM_LEFT) {
if (bottom <= prevCenter) {
distance1 = prevCenter - bottom;
} else if (top >= prevCenter) {
distance1 = top - prevCenter;
}
distance2 = left - prevRight;
} else if (prevLocation == FROM_RIGHT) {
if (bottom <= prevCenter) {
distance1 = prevCenter - bottom;
} else if (top >= prevCenter) {
distance1 = top - prevCenter;
}
distance2 = prevLeft - right;
}
if (distance1 < startEventDistance1
|| (distance1 == startEventDistance1 && distance2 < startEventDistance2)) {
startEvent = ev;
startEventDistance1 = distance1;
startEventDistance2 = distance2;
}
// For each neighbor, figure out if it is above or below or left
// or right of me and compute the distance.
for (int jj = 0; jj < len; jj++) {
if (jj == ii) {
continue;
}
Event neighbor = mSelectedEvents.get(jj);
int neighborLeft = (int) neighbor.left;
int neighborRight = (int) neighbor.right;
if (neighbor.endTime <= startTime) {
// This neighbor is entirely above me.
// If we overlap the same column, then compute the distance.
if (neighborLeft < right && neighborRight > left) {
int distance = startTime - neighbor.endTime;
if (distance < upDistanceMin) {
upDistanceMin = distance;
upEvent = neighbor;
} else if (distance == upDistanceMin) {
int center = (left + right) / 2;
int currentDistance = 0;
int currentLeft = (int) upEvent.left;
int currentRight = (int) upEvent.right;
if (currentRight <= center) {
currentDistance = center - currentRight;
} else if (currentLeft >= center) {
currentDistance = currentLeft - center;
}
int neighborDistance = 0;
if (neighborRight <= center) {
neighborDistance = center - neighborRight;
} else if (neighborLeft >= center) {
neighborDistance = neighborLeft - center;
}
if (neighborDistance < currentDistance) {
upDistanceMin = distance;
upEvent = neighbor;
}
}
}
} else if (neighbor.startTime >= endTime) {
// This neighbor is entirely below me.
// If we overlap the same column, then compute the distance.
if (neighborLeft < right && neighborRight > left) {
int distance = neighbor.startTime - endTime;
if (distance < downDistanceMin) {
downDistanceMin = distance;
downEvent = neighbor;
} else if (distance == downDistanceMin) {
int center = (left + right) / 2;
int currentDistance = 0;
int currentLeft = (int) downEvent.left;
int currentRight = (int) downEvent.right;
if (currentRight <= center) {
currentDistance = center - currentRight;
} else if (currentLeft >= center) {
currentDistance = currentLeft - center;
}
int neighborDistance = 0;
if (neighborRight <= center) {
neighborDistance = center - neighborRight;
} else if (neighborLeft >= center) {
neighborDistance = neighborLeft - center;
}
if (neighborDistance < currentDistance) {
downDistanceMin = distance;
downEvent = neighbor;
}
}
}
}
if (neighborLeft >= right) {
// This neighbor is entirely to the right of me.
// Take the closest neighbor in the y direction.
int center = (top + bottom) / 2;
int distance = 0;
int neighborBottom = (int) neighbor.bottom;
int neighborTop = (int) neighbor.top;
if (neighborBottom <= center) {
distance = center - neighborBottom;
} else if (neighborTop >= center) {
distance = neighborTop - center;
}
if (distance < rightDistanceMin) {
rightDistanceMin = distance;
rightEvent = neighbor;
} else if (distance == rightDistanceMin) {
// Pick the closest in the x direction
int neighborDistance = neighborLeft - right;
int currentDistance = (int) rightEvent.left - right;
if (neighborDistance < currentDistance) {
rightDistanceMin = distance;
rightEvent = neighbor;
}
}
} else if (neighborRight <= left) {
// This neighbor is entirely to the left of me.
// Take the closest neighbor in the y direction.
int center = (top + bottom) / 2;
int distance = 0;
int neighborBottom = (int) neighbor.bottom;
int neighborTop = (int) neighbor.top;
if (neighborBottom <= center) {
distance = center - neighborBottom;
} else if (neighborTop >= center) {
distance = neighborTop - center;
}
if (distance < leftDistanceMin) {
leftDistanceMin = distance;
leftEvent = neighbor;
} else if (distance == leftDistanceMin) {
// Pick the closest in the x direction
int neighborDistance = left - neighborRight;
int currentDistance = left - (int) leftEvent.right;
if (neighborDistance < currentDistance) {
leftDistanceMin = distance;
leftEvent = neighbor;
}
}
}
}
ev.nextUp = upEvent;
ev.nextDown = downEvent;
ev.nextLeft = leftEvent;
ev.nextRight = rightEvent;
}
mSelectedEvent = startEvent;
| void | doDown(android.view.MotionEvent ev)
mTouchMode = TOUCH_MODE_DOWN;
mViewStartX = 0;
mOnFlingCalled = false;
mLaunchNewView = false;
getHandler().removeCallbacks(mContinueScroll);
| private void | doDraw(android.graphics.Canvas canvas)
Paint p = mPaint;
Rect r = mRect;
drawGridBackground(r, canvas, p);
drawHours(r, canvas, p);
// Draw each day
int x = mHoursWidth;
int deltaX = mCellWidth + DAY_GAP;
int cell = mFirstJulianDay;
for (int day = 0; day < mNumDays; day++, cell++) {
drawEvents(cell, x, HOUR_GAP, canvas, p);
x += deltaX;
}
| void | doFling(android.view.MotionEvent e1, android.view.MotionEvent e2, float velocityX, float velocityY)
mTouchMode = TOUCH_MODE_INITIAL_STATE;
mSelectionMode = SELECTION_HIDDEN;
mOnFlingCalled = true;
int deltaX = (int) e2.getX() - (int) e1.getX();
int distanceX = Math.abs(deltaX);
int deltaY = (int) e2.getY() - (int) e1.getY();
int distanceY = Math.abs(deltaY);
if ((distanceX >= HORIZONTAL_SCROLL_THRESHOLD) && (distanceX > distanceY)) {
boolean switchForward = initNextView(deltaX);
CalendarView view = mParentActivity.getNextView();
mTitleTextView.setText(view.mDateRange);
mParentActivity.switchViews(switchForward, mViewStartX, mViewWidth);
mViewStartX = 0;
return;
}
// Continue scrolling vertically
mContinueScroll.init((int) velocityY / 20);
post(mContinueScroll);
| void | doLongPress(android.view.MotionEvent ev)
mLaunchNewView = false;
mSelectionMode = SELECTION_LONGPRESS;
mRedrawScreen = true;
invalidate();
performLongClick();
| void | doScroll(android.view.MotionEvent e1, android.view.MotionEvent e2, float deltaX, float deltaY)
mLaunchNewView = false;
// Use the distance from the current point to the initial touch instead
// of deltaX and deltaY to avoid accumulating floating-point rounding
// errors. Also, we don't need floats, we can use ints.
int distanceX = (int) e1.getX() - (int) e2.getX();
int distanceY = (int) e1.getY() - (int) e2.getY();
// If we haven't figured out the predominant scroll direction yet,
// then do it now.
if (mTouchMode == TOUCH_MODE_DOWN) {
int absDistanceX = Math.abs(distanceX);
int absDistanceY = Math.abs(distanceY);
mScrollStartY = mViewStartY;
mPreviousDistanceX = 0;
mPreviousDirection = 0;
// If the x distance is at least twice the y distance, then lock
// the scroll horizontally. Otherwise scroll vertically.
if (absDistanceX >= 2 * absDistanceY) {
mTouchMode = TOUCH_MODE_HSCROLL;
mViewStartX = distanceX;
initNextView(-mViewStartX);
} else {
mTouchMode = TOUCH_MODE_VSCROLL;
}
} else if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
// We are already scrolling horizontally, so check if we
// changed the direction of scrolling so that the other week
// is now visible.
mViewStartX = distanceX;
if (distanceX != 0) {
int direction = (distanceX > 0) ? 1 : -1;
if (direction != mPreviousDirection) {
// The user has switched the direction of scrolling
// so re-init the next view
initNextView(-mViewStartX);
mPreviousDirection = direction;
}
}
// If we have moved at least the HORIZONTAL_SCROLL_THRESHOLD,
// then change the title to the new day (or week), but only
// if we haven't already changed the title.
if (distanceX >= HORIZONTAL_SCROLL_THRESHOLD) {
if (mPreviousDistanceX < HORIZONTAL_SCROLL_THRESHOLD) {
CalendarView view = mParentActivity.getNextView();
mTitleTextView.setText(view.mDateRange);
}
} else if (distanceX <= -HORIZONTAL_SCROLL_THRESHOLD) {
if (mPreviousDistanceX > -HORIZONTAL_SCROLL_THRESHOLD) {
CalendarView view = mParentActivity.getNextView();
mTitleTextView.setText(view.mDateRange);
}
} else {
if (mPreviousDistanceX >= HORIZONTAL_SCROLL_THRESHOLD
|| mPreviousDistanceX <= -HORIZONTAL_SCROLL_THRESHOLD) {
mTitleTextView.setText(mDateRange);
}
}
mPreviousDistanceX = distanceX;
}
if ((mTouchMode & TOUCH_MODE_VSCROLL) != 0) {
mViewStartY = mScrollStartY + distanceY;
if (mViewStartY < 0) {
mViewStartY = 0;
} else if (mViewStartY > mMaxViewStartY) {
mViewStartY = mMaxViewStartY;
}
computeFirstHour();
}
mScrolling = true;
if (mSelectionMode != SELECTION_HIDDEN) {
mSelectionMode = SELECTION_HIDDEN;
mRedrawScreen = true;
}
invalidate();
| void | doShowPress(android.view.MotionEvent ev)
int x = (int) ev.getX();
int y = (int) ev.getY();
Event selectedEvent = mSelectedEvent;
int selectedDay = mSelectionDay;
int selectedHour = mSelectionHour;
boolean validPosition = setSelectionFromPosition(x, y);
if (!validPosition) {
return;
}
mSelectionMode = SELECTION_PRESSED;
mRedrawScreen = true;
invalidate();
// If the tap is on an already selected event or hour slot,
// then launch a new view. Otherwise, just select the event.
if (selectedEvent != null && selectedEvent == mSelectedEvent) {
// Launch the "View event" view when the finger lifts up,
// unless the finger moves before lifting up.
mLaunchNewView = true;
} else if (selectedEvent == null && selectedDay == mSelectionDay
&& selectedHour == mSelectionHour) {
// Launch the Day/Agenda view when the finger lifts up,
// unless the finger moves before lifting up.
mLaunchNewView = true;
}
| void | doSingleTapUp(android.view.MotionEvent ev)
mSelectionMode = SELECTION_SELECTED;
mRedrawScreen = true;
invalidate();
if (mLaunchNewView) {
mLaunchNewView = false;
switchViews(false /* not the trackball */);
}
| private void | drawAfterScroll(android.graphics.Canvas canvas)
Paint p = mPaint;
Rect r = mRect;
if (mMaxAllDayEvents != 0) {
drawAllDayEvents(mFirstJulianDay, mNumDays, r, canvas, p);
drawUpperLeftCorner(r, canvas, p);
}
if (mNumDays > 1) {
drawDayHeaderLoop(r, canvas, p);
}
// Draw the AM and PM indicators if we're in 12 hour mode
if (!mIs24HourFormat) {
drawAmPm(canvas, p);
}
// Update the popup window showing the event details, but only if
// we are not scrolling and we have focus.
if (!mScrolling && isFocused()) {
updateEventDetails();
}
| android.graphics.RectF | drawAllDayEventRect(Event event, android.graphics.Canvas canvas, android.graphics.Paint p, android.graphics.Paint eventTextPaint)
// If this event is selected, then use the selection color
if (mSelectedEvent == event) {
// Also, remember the last selected event that we drew
mPrevSelectedEvent = event;
p.setColor(mSelectionColor);
eventTextPaint.setColor(mSelectedEventTextColor);
} else {
// Use the normal color for all-day events
p.setColor(event.color);
eventTextPaint.setColor(mEventTextColor);
}
RectF rf = mRectF;
rf.top = event.top;
rf.bottom = event.bottom;
rf.left = event.left;
rf.right = event.right;
canvas.drawRoundRect(rf, SMALL_ROUND_RADIUS, SMALL_ROUND_RADIUS, p);
rf.left += 2;
rf.right -= 2;
return rf;
| private void | drawAllDayEvents(int firstDay, int numDays, android.graphics.Rect r, android.graphics.Canvas canvas, android.graphics.Paint p)
p.setTextSize(NORMAL_FONT_SIZE);
p.setTextAlign(Paint.Align.LEFT);
Paint eventTextPaint = mEventTextPaint;
// Draw the background for the all-day events area
r.top = mBannerPlusMargin;
r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
r.left = mHoursWidth;
r.right = r.left + mNumDays * (mCellWidth + DAY_GAP);
p.setColor(mResources.getColor(R.color.calendar_all_day_background));
canvas.drawRect(r, p);
// Fill the extra space on the right side with the default background
r.left = r.right;
r.right = mViewWidth;
p.setColor(mResources.getColor(R.color.calendar_grid_area_background));
canvas.drawRect(r, p);
// Draw the vertical grid lines
p.setColor(mResources.getColor(R.color.calendar_grid_line_vertical_color));
p.setStyle(Style.STROKE);
p.setStrokeWidth(0);
p.setAntiAlias(false);
float startY = r.top;
float stopY = r.bottom;
float deltaX = mCellWidth + DAY_GAP;
float x = mHoursWidth + mCellWidth;
for (int day = 0; day <= mNumDays; day++) {
canvas.drawLine(x, startY, x, stopY, p);
x += deltaX;
}
p.setAntiAlias(true);
p.setStyle(Style.FILL);
int y = mBannerPlusMargin + ALLDAY_TOP_MARGIN;
float left = mHoursWidth;
int lastDay = firstDay + numDays - 1;
ArrayList<Event> events = mEvents;
int numEvents = events.size();
float drawHeight = mAllDayHeight;
float numRectangles = mMaxAllDayEvents;
for (int i = 0; i < numEvents; i++) {
Event event = events.get(i);
if (!event.allDay)
continue;
int startDay = event.startDay;
int endDay = event.endDay;
if (startDay > lastDay || endDay < firstDay)
continue;
if (startDay < firstDay)
startDay = firstDay;
if (endDay > lastDay)
endDay = lastDay;
int startIndex = startDay - firstDay;
int endIndex = endDay - firstDay;
float height = drawHeight / numRectangles;
// Prevent a single event from getting too big
if (height > MAX_ALLDAY_EVENT_HEIGHT) {
height = MAX_ALLDAY_EVENT_HEIGHT;
}
// Leave a one-pixel space between the vertical day lines and the
// event rectangle.
event.left = left + startIndex * (mCellWidth + DAY_GAP) + 2;
event.right = left + endIndex * (mCellWidth + DAY_GAP) + mCellWidth - 1;
event.top = y + height * event.getColumn();
// Multiply the height by 0.9 to leave a little gap between events
event.bottom = event.top + height * 0.9f;
RectF rf = drawAllDayEventRect(event, canvas, p, eventTextPaint);
drawEventText(event, rf, canvas, eventTextPaint, ALL_DAY_TEXT_TOP_MARGIN);
// Check if this all-day event intersects the selected day
if (mSelectionAllDay && mComputeSelectedEvents) {
if (startDay <= mSelectionDay && endDay >= mSelectionDay) {
mSelectedEvents.add(event);
}
}
}
if (mSelectionAllDay) {
// Compute the neighbors for the list of all-day events that
// intersect the selected day.
computeAllDayNeighbors();
if (mSelectedEvent != null) {
Event event = mSelectedEvent;
RectF rf = drawAllDayEventRect(event, canvas, p, eventTextPaint);
drawEventText(event, rf, canvas, eventTextPaint, ALL_DAY_TEXT_TOP_MARGIN);
}
// Draw the highlight on the selected all-day area
float top = mBannerPlusMargin + 1;
float bottom = top + mAllDayHeight + ALLDAY_TOP_MARGIN - 1;
int daynum = mSelectionDay - mFirstJulianDay;
left = mHoursWidth + daynum * (mCellWidth + DAY_GAP) + 1;
float right = left + mCellWidth + DAY_GAP - 1;
if (mNumDays == 1) {
// The Day view doesn't have a vertical line on the right.
right -= 1;
}
Path path = mPath;
path.reset();
path.addRect(left, top, right, bottom, Direction.CW);
canvas.drawPath(path, mSelectionPaint);
// Set the selection position to zero so that when we move down
// to the normal event area, we will highlight the topmost event.
saveSelectionPosition(0f, 0f, 0f, 0f);
}
| private void | drawAmPm(android.graphics.Canvas canvas, android.graphics.Paint p)
p.setColor(mResources.getColor(R.color.calendar_ampm_label));
p.setTextSize(AMPM_FONT_SIZE);
p.setTypeface(mBold);
p.setAntiAlias(true);
mPaint.setTextAlign(Paint.Align.RIGHT);
String text = mAmString;
if (mFirstHour >= 12) {
text = mPmString;
}
int y = mFirstCell + mFirstHourOffset + 2 * mHoursTextHeight + HOUR_GAP;
int right = mHoursWidth - HOURS_RIGHT_MARGIN;
canvas.drawText(text, right, y, p);
if (mFirstHour < 12 && mFirstHour + mNumHours > 12) {
// Also draw the "PM"
text = mPmString;
y = mFirstCell + mFirstHourOffset + (12 - mFirstHour) * (mCellHeight + HOUR_GAP)
+ 2 * mHoursTextHeight + HOUR_GAP;
canvas.drawText(text, right, y, p);
}
| private void | drawCalendarView(android.graphics.Canvas canvas)
// Copy the scrollable region from the big bitmap to the canvas.
Rect src = mSrcRect;
Rect dest = mDestRect;
src.top = mViewStartY;
src.bottom = mViewStartY + mGridAreaHeight;
src.left = 0;
src.right = mViewWidth;
dest.top = mFirstCell;
dest.bottom = mViewHeight;
dest.left = 0;
dest.right = mViewWidth;
canvas.save();
canvas.clipRect(dest);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawBitmap(mBitmap, src, dest, null);
canvas.restore();
| private void | drawDayHeader(java.lang.String dateStr, int day, int cell, int x, android.graphics.Canvas canvas, android.graphics.Paint p)
float xCenter = x + mCellWidth / 2.0f;
p.setTypeface(mBold);
p.setAntiAlias(true);
boolean isWeekend = false;
if ((mStartDay == Time.SUNDAY && (day == 0 || day == 6))
|| (mStartDay == Time.MONDAY && (day == 5 || day == 6))
|| (mStartDay == Time.SATURDAY && (day == 0 || day == 1))) {
isWeekend = true;
}
if (isWeekend) {
p.setColor(mResources.getColor(R.color.week_weekend));
} else {
p.setColor(mResources.getColor(R.color.calendar_date_banner_text_color));
}
int dateNum = mFirstDate + day;
if (dateNum > mMonthLength) {
dateNum -= mMonthLength;
}
String dateNumStr;
// Add a leading zero if the date is a single digit
if (dateNum < 10) {
dateNumStr = "0" + dateNum;
} else {
dateNumStr = String.valueOf(dateNum);
}
dateStr = getResources().getString(R.string.weekday_day,
dateStr, dateNumStr);
float y = mBannerPlusMargin - 7;
canvas.drawText(dateStr, xCenter, y, p);
| private void | drawDayHeaderLoop(android.graphics.Rect r, android.graphics.Canvas canvas, android.graphics.Paint p)
// Draw the horizontal day background banner
p.setColor(mResources.getColor(R.color.calendar_date_banner_background));
r.top = 0;
r.bottom = mBannerPlusMargin;
r.left = 0;
r.right = mHoursWidth + mNumDays * (mCellWidth + DAY_GAP);
canvas.drawRect(r, p);
// Fill the extra space on the right side with the default background
r.left = r.right;
r.right = mViewWidth;
p.setColor(mResources.getColor(R.color.calendar_grid_area_background));
canvas.drawRect(r, p);
// Draw a highlight on the selected day (if any), but only if we are
// displaying more than one day.
if (mSelectionMode != SELECTION_HIDDEN) {
if (mNumDays > 1) {
p.setColor(mResources.getColor(R.color.calendar_date_selected));
r.top = 0;
r.bottom = mBannerPlusMargin;
int daynum = mSelectionDay - mFirstJulianDay;
r.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
r.right = r.left + mCellWidth;
canvas.drawRect(r, p);
}
}
p.setTextSize(NORMAL_FONT_SIZE);
p.setTextAlign(Paint.Align.CENTER);
int x = mHoursWidth;
int deltaX = mCellWidth + DAY_GAP;
int cell = mFirstJulianDay;
String[] dayNames;
if (mDateStrWidth < mCellWidth) {
dayNames = mDayStrs;
} else {
dayNames = mDayStrs2Letter;
}
for (int day = 0; day < mNumDays; day++, cell++) {
drawDayHeader(dayNames[day + mStartDay], day, cell, x, canvas, p);
x += deltaX;
}
| private android.graphics.RectF | drawEventRect(Event event, android.graphics.Canvas canvas, android.graphics.Paint p, android.graphics.Paint eventTextPaint)
int color = event.color;
// Fade visible boxes if event was declined.
boolean declined = (event.selfAttendeeStatus == Attendees.ATTENDEE_STATUS_DECLINED);
if (declined) {
int alpha = color & 0xff000000;
color &= 0x00ffffff;
int red = (color & 0x00ff0000) >> 16;
int green = (color & 0x0000ff00) >> 8;
int blue = (color & 0x0000ff);
color = ((red >> 1) << 16) | ((green >> 1) << 8) | (blue >> 1);
color += 0x7F7F7F + alpha;
}
// If this event is selected, then use the selection color
if (mSelectedEvent == event) {
if (mSelectionMode == SELECTION_PRESSED) {
// Also, remember the last selected event that we drew
mPrevSelectedEvent = event;
// box = mBoxPressed;
p.setColor(mPressedColor); // FIXME:pressed
eventTextPaint.setColor(mSelectedEventTextColor);
} else if (mSelectionMode == SELECTION_SELECTED) {
// Also, remember the last selected event that we drew
mPrevSelectedEvent = event;
// box = mBoxSelected;
p.setColor(mSelectionColor);
eventTextPaint.setColor(mSelectedEventTextColor);
} else if (mSelectionMode == SELECTION_LONGPRESS) {
// box = mBoxLongPressed;
p.setColor(mPressedColor); // FIXME: longpressed (maybe -- this doesn't seem to work)
eventTextPaint.setColor(mSelectedEventTextColor);
} else {
p.setColor(color);
eventTextPaint.setColor(mEventTextColor);
}
} else {
p.setColor(color);
eventTextPaint.setColor(mEventTextColor);
}
RectF rf = mRectF;
rf.top = event.top;
rf.bottom = event.bottom;
rf.left = event.left;
rf.right = event.right - 1;
canvas.drawRoundRect(rf, SMALL_ROUND_RADIUS, SMALL_ROUND_RADIUS, p);
// Draw a darker border
float[] hsv = new float[3];
Color.colorToHSV(p.getColor(), hsv);
hsv[1] = 1.0f;
hsv[2] *= 0.75f;
mPaintBorder.setColor(Color.HSVToColor(hsv));
canvas.drawRoundRect(rf, SMALL_ROUND_RADIUS, SMALL_ROUND_RADIUS, mPaintBorder);
rf.left += 2;
rf.right -= 2;
return rf;
| private void | drawEventText(Event event, android.graphics.RectF rf, android.graphics.Canvas canvas, android.graphics.Paint p, int topMargin)
if (!mDrawTextInEventRect) {
return;
}
float width = rf.right - rf.left;
float height = rf.bottom - rf.top;
// Leave one pixel extra space between lines
int lineHeight = mEventTextHeight + 1;
// If the rectangle is too small for text, then return
if (width < MIN_CELL_WIDTH_FOR_TEXT || height <= lineHeight) {
return;
}
// Truncate the event title to a known (large enough) limit
String text = event.getTitleAndLocation();
int len = text.length();
if (len > MAX_EVENT_TEXT_LEN) {
text = text.substring(0, MAX_EVENT_TEXT_LEN);
len = MAX_EVENT_TEXT_LEN;
}
// Figure out how much space the event title will take, and create a
// String fragment that will fit in the rectangle. Use multiple lines,
// if available.
p.getTextWidths(text, mCharWidths);
String fragment = text;
float top = rf.top + mEventTextAscent + topMargin;
int start = 0;
// Leave one pixel extra space at the bottom
while (start < len && height >= (lineHeight + 1)) {
boolean lastLine = (height < 2 * lineHeight + 1);
// Skip leading spaces at the beginning of each line
do {
char c = text.charAt(start);
if (c != ' ") break;
start += 1;
} while (start < len);
float sum = 0;
int end = start;
for (int ii = start; ii < len; ii++) {
char c = text.charAt(ii);
// If we found the end of a word, then remember the ending
// position.
if (c == ' ") {
end = ii;
}
sum += mCharWidths[ii];
// If adding this character would exceed the width and this
// isn't the last line, then break the line at the previous
// word. If there was no previous word, then break this word.
if (sum > width) {
if (end > start && !lastLine) {
// There was a previous word on this line.
fragment = text.substring(start, end);
start = end;
break;
}
// This is the only word and it is too long to fit on
// the line (or this is the last line), so take as many
// characters of this word as will fit.
fragment = text.substring(start, ii);
start = ii;
break;
}
}
// If sum <= width, then we can fit the rest of the text on
// this line.
if (sum <= width) {
fragment = text.substring(start, len);
start = len;
}
canvas.drawText(fragment, rf.left + 1, top, p);
top += lineHeight;
height -= lineHeight;
}
| private void | drawEvents(int date, int left, int top, android.graphics.Canvas canvas, android.graphics.Paint p)
Paint eventTextPaint = mEventTextPaint;
int cellWidth = mCellWidth;
int cellHeight = mCellHeight;
// Use the selected hour as the selection region
Rect selectionArea = mRect;
selectionArea.top = top + mSelectionHour * (cellHeight + HOUR_GAP);
selectionArea.bottom = selectionArea.top + cellHeight;
selectionArea.left = left;
selectionArea.right = selectionArea.left + cellWidth;
ArrayList<Event> events = mEvents;
int numEvents = events.size();
EventGeometry geometry = mEventGeometry;
for (int i = 0; i < numEvents; i++) {
Event event = events.get(i);
if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
continue;
}
if (date == mSelectionDay && !mSelectionAllDay && mComputeSelectedEvents
&& geometry.eventIntersectsSelection(event, selectionArea)) {
mSelectedEvents.add(event);
}
RectF rf = drawEventRect(event, canvas, p, eventTextPaint);
drawEventText(event, rf, canvas, eventTextPaint, NORMAL_TEXT_TOP_MARGIN);
}
if (date == mSelectionDay && !mSelectionAllDay && isFocused()
&& mSelectionMode != SELECTION_HIDDEN) {
computeNeighbors();
if (mSelectedEvent != null) {
RectF rf = drawEventRect(mSelectedEvent, canvas, p, eventTextPaint);
drawEventText(mSelectedEvent, rf, canvas, eventTextPaint, NORMAL_TEXT_TOP_MARGIN);
}
}
| private void | drawGridBackground(android.graphics.Rect r, android.graphics.Canvas canvas, android.graphics.Paint p)
Paint.Style savedStyle = p.getStyle();
// Clear the background
p.setColor(mResources.getColor(R.color.calendar_grid_area_background));
r.top = 0;
r.bottom = mBitmapHeight;
r.left = 0;
r.right = mViewWidth;
canvas.drawRect(r, p);
// Draw the horizontal grid lines
p.setColor(mResources.getColor(R.color.calendar_grid_line_horizontal_color));
p.setStyle(Style.STROKE);
p.setStrokeWidth(0);
p.setAntiAlias(false);
float startX = mHoursWidth;
float stopX = mHoursWidth + (mCellWidth + DAY_GAP) * mNumDays;
float y = 0;
float deltaY = mCellHeight + HOUR_GAP;
for (int hour = 0; hour <= 24; hour++) {
canvas.drawLine(startX, y, stopX, y, p);
y += deltaY;
}
// Draw the vertical grid lines
p.setColor(mResources.getColor(R.color.calendar_grid_line_vertical_color));
float startY = 0;
float stopY = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP);
float deltaX = mCellWidth + DAY_GAP;
float x = mHoursWidth + mCellWidth;
for (int day = 0; day < mNumDays; day++) {
canvas.drawLine(x, startY, x, stopY, p);
x += deltaX;
}
// Restore the saved style.
p.setStyle(savedStyle);
p.setAntiAlias(true);
| private void | drawHours(android.graphics.Rect r, android.graphics.Canvas canvas, android.graphics.Paint p)
// Draw the background for the hour labels
p.setColor(mResources.getColor(R.color.calendar_hour_background));
r.top = 0;
r.bottom = 24 * (mCellHeight + HOUR_GAP) + HOUR_GAP;
r.left = 0;
r.right = mHoursWidth;
canvas.drawRect(r, p);
// Fill the bottom left corner with the default grid background
r.top = r.bottom;
r.bottom = mBitmapHeight;
p.setColor(mResources.getColor(R.color.calendar_grid_area_background));
canvas.drawRect(r, p);
// Draw a highlight on the selected hour (if needed)
if (mSelectionMode != SELECTION_HIDDEN && !mSelectionAllDay) {
p.setColor(mResources.getColor(R.color.calendar_hour_selected));
r.top = mSelectionHour * (mCellHeight + HOUR_GAP);
r.bottom = r.top + mCellHeight + 2 * HOUR_GAP;
r.left = 0;
r.right = mHoursWidth;
canvas.drawRect(r, p);
// Also draw the highlight on the grid
p.setColor(mResources.getColor(R.color.calendar_grid_area_selected));
int daynum = mSelectionDay - mFirstJulianDay;
r.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
r.right = r.left + mCellWidth;
canvas.drawRect(r, p);
// Draw a border around the highlighted grid hour.
Path path = mPath;
r.top += HOUR_GAP;
r.bottom -= HOUR_GAP;
path.reset();
path.addRect(r.left, r.top, r.right, r.bottom, Direction.CW);
canvas.drawPath(path, mSelectionPaint);
saveSelectionPosition(r.left, r.top, r.right, r.bottom);
}
p.setColor(mResources.getColor(R.color.calendar_hour_label));
p.setTextSize(HOURS_FONT_SIZE);
p.setTypeface(mBold);
p.setTextAlign(Paint.Align.RIGHT);
p.setAntiAlias(true);
int right = mHoursWidth - HOURS_RIGHT_MARGIN;
int y = HOUR_GAP + mHoursTextHeight;
for (int i = 0; i < 24; i++) {
String time = mHourStrs[i];
canvas.drawText(time, right, y, p);
y += mCellHeight + HOUR_GAP;
}
| private void | drawUpperLeftCorner(android.graphics.Rect r, android.graphics.Canvas canvas, android.graphics.Paint p)
p.setColor(mResources.getColor(R.color.calendar_hour_background));
r.top = mBannerPlusMargin;
r.bottom = r.top + mAllDayHeight + ALLDAY_TOP_MARGIN;
r.left = 0;
r.right = mHoursWidth;
canvas.drawRect(r, p);
| private void | findSelectedEvent(int x, int y)
int date = mSelectionDay;
int cellWidth = mCellWidth;
ArrayList<Event> events = mEvents;
int numEvents = events.size();
int left = mHoursWidth + (mSelectionDay - mFirstJulianDay) * (cellWidth + DAY_GAP);
int top = 0;
mSelectedEvent = null;
mSelectedEvents.clear();
if (mSelectionAllDay) {
float yDistance;
float minYdistance = 10000.0f; // any large number
Event closestEvent = null;
float drawHeight = mAllDayHeight;
int yOffset = mBannerPlusMargin + ALLDAY_TOP_MARGIN;
for (int i = 0; i < numEvents; i++) {
Event event = events.get(i);
if (!event.allDay) {
continue;
}
if (event.startDay <= mSelectionDay && event.endDay >= mSelectionDay) {
float numRectangles = event.getMaxColumns();
float height = drawHeight / numRectangles;
if (height > MAX_ALLDAY_EVENT_HEIGHT) {
height = MAX_ALLDAY_EVENT_HEIGHT;
}
float eventTop = yOffset + height * event.getColumn();
float eventBottom = eventTop + height;
if (eventTop < y && eventBottom > y) {
// If the touch is inside the event rectangle, then
// add the event.
mSelectedEvents.add(event);
closestEvent = event;
break;
} else {
// Find the closest event
if (eventTop >= y) {
yDistance = eventTop - y;
} else {
yDistance = y - eventBottom;
}
if (yDistance < minYdistance) {
minYdistance = yDistance;
closestEvent = event;
}
}
}
}
mSelectedEvent = closestEvent;
return;
}
// Adjust y for the scrollable bitmap
y += mViewStartY - mFirstCell;
// Use a region around (x,y) for the selection region
Rect region = mRect;
region.left = x - 10;
region.right = x + 10;
region.top = y - 10;
region.bottom = y + 10;
EventGeometry geometry = mEventGeometry;
for (int i = 0; i < numEvents; i++) {
Event event = events.get(i);
// Compute the event rectangle.
if (!geometry.computeEventRect(date, left, top, cellWidth, event)) {
continue;
}
// If the event intersects the selection region, then add it to
// mSelectedEvents.
if (geometry.eventIntersectsSelection(event, region)) {
mSelectedEvents.add(event);
}
}
// If there are any events in the selected region, then assign the
// closest one to mSelectedEvent.
if (mSelectedEvents.size() > 0) {
int len = mSelectedEvents.size();
Event closestEvent = null;
float minDist = mViewWidth + mViewHeight; // some large distance
for (int index = 0; index < len; index++) {
Event ev = mSelectedEvents.get(index);
float dist = geometry.pointToEvent(x, y, ev);
if (dist < minDist) {
minDist = dist;
closestEvent = ev;
}
}
mSelectedEvent = closestEvent;
// Keep the selected hour and day consistent with the selected
// event. They could be different if we touched on an empty hour
// slot very close to an event in the previous hour slot. In
// that case we will select the nearby event.
int startDay = mSelectedEvent.startDay;
int endDay = mSelectedEvent.endDay;
if (mSelectionDay < startDay) {
mSelectionDay = startDay;
} else if (mSelectionDay > endDay) {
mSelectionDay = endDay;
}
int startHour = mSelectedEvent.startTime / 60;
int endHour;
if (mSelectedEvent.startTime < mSelectedEvent.endTime) {
endHour = (mSelectedEvent.endTime - 1) / 60;
} else {
endHour = mSelectedEvent.endTime / 60;
}
if (mSelectionHour < startHour) {
mSelectionHour = startHour;
} else if (mSelectionHour > endHour) {
mSelectionHour = endHour;
}
}
| private android.graphics.Rect | getCurrentSelectionPosition()
Rect box = new Rect();
box.top = mSelectionHour * (mCellHeight + HOUR_GAP);
box.bottom = box.top + mCellHeight + HOUR_GAP;
int daynum = mSelectionDay - mFirstJulianDay;
box.left = mHoursWidth + daynum * (mCellWidth + DAY_GAP);
box.right = box.left + mCellWidth + DAY_GAP;
return box;
| Event | getNewEvent()
return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
getSelectedMinutesSinceMidnight());
| static Event | getNewEvent(int julianDay, long utcMillis, int minutesSinceMidnight)
Event event = Event.newInstance();
event.startDay = julianDay;
event.endDay = julianDay;
event.startMillis = utcMillis;
event.endMillis = event.startMillis + MILLIS_PER_HOUR;
event.startTime = minutesSinceMidnight;
event.endTime = event.startTime + MINUTES_PER_HOUR;
return event;
| public android.text.format.Time | getSelectedDay()
Time time = new Time(mBaseDate);
time.setJulianDay(mSelectionDay);
time.hour = mSelectionHour;
// We ignore the "isDst" field because we want normalize() to figure
// out the correct DST value and not adjust the selected time based
// on the current setting of DST.
time.normalize(true /* ignore isDst */);
return time;
| Event | getSelectedEvent()
if (mSelectedEvent == null) {
// There is no event at the selected hour, so create a new event.
return getNewEvent(mSelectionDay, getSelectedTimeInMillis(),
getSelectedMinutesSinceMidnight());
}
return mSelectedEvent;
| int | getSelectedMinutesSinceMidnight()Returns the start of the selected time in minutes since midnight,
local time. The derived class must ensure that this is consistent
with the return value from getSelectedTimeInMillis().
return mSelectionHour * MINUTES_PER_HOUR;
| android.text.format.Time | getSelectedTime()
Time time = new Time(mBaseDate);
time.setJulianDay(mSelectionDay);
time.hour = mSelectionHour;
// We ignore the "isDst" field because we want normalize() to figure
// out the correct DST value and not adjust the selected time based
// on the current setting of DST.
time.normalize(true /* ignore isDst */);
return time;
| long | getSelectedTimeInMillis()Returns the start of the selected time in milliseconds since the epoch.
Time time = new Time(mBaseDate);
time.setJulianDay(mSelectionDay);
time.hour = mSelectionHour;
// We ignore the "isDst" field because we want normalize() to figure
// out the correct DST value and not adjust the selected time based
// on the current setting of DST.
return time.normalize(true /* ignore isDst */);
| private void | init(android.content.Context context)
setFocusable(true);
// Allow focus in touch mode so that we can do keyboard shortcuts
// even after we've entered touch mode.
setFocusableInTouchMode(true);
setClickable(true);
setOnCreateContextMenuListener(this);
mStartDay = Calendar.getInstance().getFirstDayOfWeek();
if (mStartDay == Calendar.SATURDAY) {
mStartDay = Time.SATURDAY;
} else if (mStartDay == Calendar.MONDAY) {
mStartDay = Time.MONDAY;
} else {
mStartDay = Time.SUNDAY;
}
mSelectionColor = mResources.getColor(R.color.selection);
mPressedColor = mResources.getColor(R.color.pressed);
mSelectedEventTextColor = mResources.getColor(R.color.calendar_event_selected_text_color);
mEventTextColor = mResources.getColor(R.color.calendar_event_text_color);
mEventTextPaint.setColor(mEventTextColor);
mEventTextPaint.setTextSize(EVENT_TEXT_FONT_SIZE);
mEventTextPaint.setTextAlign(Paint.Align.LEFT);
mEventTextPaint.setAntiAlias(true);
int gridLineColor = mResources.getColor(R.color.calendar_grid_line_highlight_color);
Paint p = mSelectionPaint;
p.setColor(gridLineColor);
p.setStyle(Style.STROKE);
p.setStrokeWidth(2.0f);
p.setAntiAlias(false);
p = mPaint;
p.setAntiAlias(true);
mPaintBorder.setColor(0xffc8c8c8);
mPaintBorder.setStyle(Style.STROKE);
mPaintBorder.setAntiAlias(true);
mPaintBorder.setStrokeWidth(2.0f);
// Allocate space for 2 weeks worth of weekday names so that we can
// easily start the week display at any week day.
mDayStrs = new String[14];
// Also create an array of 2-letter abbreviations.
mDayStrs2Letter = new String[14];
for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
int index = i - Calendar.SUNDAY;
// e.g. Tue for Tuesday
mDayStrs[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_MEDIUM);
mDayStrs[index + 7] = mDayStrs[index];
// e.g. Tu for Tuesday
mDayStrs2Letter[index] = DateUtils.getDayOfWeekString(i, DateUtils.LENGTH_SHORT);
mDayStrs2Letter[index + 7] = mDayStrs2Letter[index];
}
// Figure out how much space we need for the 3-letter abbrev names
// in the worst case.
p.setTextSize(NORMAL_FONT_SIZE);
p.setTypeface(mBold);
String[] dateStrs = {" 28", " 30"};
mDateStrWidth = computeMaxStringWidth(0, dateStrs, p);
mDateStrWidth += computeMaxStringWidth(0, mDayStrs, p);
p.setTextSize(HOURS_FONT_SIZE);
p.setTypeface(null);
mIs24HourFormat = DateFormat.is24HourFormat(context);
mHourStrs = mIs24HourFormat ? CalendarData.s24Hours : CalendarData.s12HoursNoAmPm;
mHoursWidth = computeMaxStringWidth(0, mHourStrs, p);
mAmString = DateUtils.getAMPMString(Calendar.AM);
mPmString = DateUtils.getAMPMString(Calendar.PM);
String[] ampm = {mAmString, mPmString};
p.setTextSize(AMPM_FONT_SIZE);
mHoursWidth = computeMaxStringWidth(mHoursWidth, ampm, p);
mHoursWidth += HOURS_MARGIN;
LayoutInflater inflater;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPopupView = inflater.inflate(R.layout.bubble_event, null);
mPopupView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
mPopup = new PopupWindow(context);
mPopup.setContentView(mPopupView);
Resources.Theme dialogTheme = getResources().newTheme();
dialogTheme.applyStyle(android.R.style.Theme_Dialog, true);
TypedArray ta = dialogTheme.obtainStyledAttributes(new int[] {
android.R.attr.windowBackground });
mPopup.setBackgroundDrawable(ta.getDrawable(0));
ta.recycle();
// Enable touching the popup window
mPopupView.setOnClickListener(this);
mBaseDate = new Time();
long millis = System.currentTimeMillis();
mBaseDate.set(millis);
mEarliestStartHour = new int[mNumDays];
mHasAllDayEvent = new boolean[mNumDays];
mNumHours = context.getResources().getInteger(R.integer.number_of_hours);
mTitleTextView = (TextView) mParentActivity.findViewById(R.id.title);
| private void | initFirstHour()
mFirstHour = mSelectionHour - mNumHours / 2;
if (mFirstHour < 0) {
mFirstHour = 0;
} else if (mFirstHour + mNumHours > 24) {
mFirstHour = 24 - mNumHours;
}
| private boolean | initNextView(int deltaX)
// Change the view to the previous day or week
CalendarView view = mParentActivity.getNextView();
Time date = view.mBaseDate;
date.set(mBaseDate);
boolean switchForward;
if (deltaX > 0) {
date.monthDay -= mNumDays;
view.mSelectionDay = mSelectionDay - mNumDays;
switchForward = false;
} else {
date.monthDay += mNumDays;
view.mSelectionDay = mSelectionDay + mNumDays;
switchForward = true;
}
date.normalize(true /* ignore isDst */);
initView(view);
view.setFrame(getLeft(), getTop(), getRight(), getBottom());
view.reloadEvents();
return switchForward;
| private void | initView(com.android.calendar.CalendarView view)Initialize the state for another view. The given view is one that has
its own bitmap and will use an animation to replace the current view.
The current view and new view are either both Week views or both Day
views. They differ in their base date.
view.mSelectionHour = mSelectionHour;
view.mSelectedEvents.clear();
view.mComputeSelectedEvents = true;
view.mFirstHour = mFirstHour;
view.mFirstHourOffset = mFirstHourOffset;
view.remeasure(getWidth(), getHeight());
view.mSelectedEvent = null;
view.mPrevSelectedEvent = null;
view.mStartDay = mStartDay;
if (view.mEvents.size() > 0) {
view.mSelectionAllDay = mSelectionAllDay;
} else {
view.mSelectionAllDay = false;
}
// Redraw the screen so that the selection box will be redrawn. We may
// have scrolled to a different part of the day in some other view
// so the selection box in this view may no longer be visible.
view.mRedrawScreen = true;
view.recalc();
| private static boolean | isEventEditable(android.content.Context context, Event e)
ContentResolver cr = context.getContentResolver();
int visibility = Calendars.NO_ACCESS;
int relationship = Attendees.RELATIONSHIP_ORGANIZER;
// Get the calendar id for this event
Cursor cursor = cr.query(ContentUris.withAppendedId(Events.CONTENT_URI, e.id),
new String[] { Events.CALENDAR_ID },
null /* selection */,
null /* selectionArgs */,
null /* sort */);
if ((cursor == null) || (cursor.getCount() == 0)) {
return false;
}
cursor.moveToFirst();
long calId = cursor.getLong(0);
cursor.deactivate();
Uri uri = Calendars.CONTENT_URI;
String where = String.format(CALENDARS_WHERE, calId);
cursor = cr.query(uri, CALENDARS_PROJECTION, where, null, null);
if (cursor != null) {
cursor.moveToFirst();
visibility = cursor.getInt(CALENDARS_INDEX_ACCESS_LEVEL);
cursor.close();
}
// Attendees cursor
uri = Attendees.CONTENT_URI;
where = String.format(ATTENDEES_WHERE, e.id);
Cursor attendeesCursor = cr.query(uri, ATTENDEES_PROJECTION, where, null, null);
if (attendeesCursor != null) {
if (attendeesCursor.moveToFirst()) {
relationship = attendeesCursor.getInt(ATTENDEES_INDEX_RELATIONSHIP);
}
attendeesCursor.close();
}
return visibility >= Calendars.CONTRIBUTOR_ACCESS &&
relationship >= Attendees.RELATIONSHIP_ORGANIZER;
| boolean | isEventSelected()
return (mSelectedEvent != null);
| public void | onClick(android.view.View v)This is called when the popup window is pressed.
if (v == mPopupView) {
// Pretend it was a trackball click because that will always
// jump to the "View event" screen.
switchViews(true /* trackball */);
}
| public void | onCreateContextMenu(android.view.ContextMenu menu, android.view.View view, android.view.ContextMenu.ContextMenuInfo menuInfo)
MenuItem item;
// If the trackball is held down, then the context menu pops up and
// we never get onKeyUp() for the long-press. So check for it here
// and change the selection to the long-press state.
if (mSelectionMode != SELECTION_LONGPRESS) {
mSelectionMode = SELECTION_LONGPRESS;
mRedrawScreen = true;
invalidate();
}
final long startMillis = getSelectedTimeInMillis();
int flags = DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_CAP_NOON_MIDNIGHT
| DateUtils.FORMAT_SHOW_WEEKDAY;
final String title = DateUtils.formatDateTime(mParentActivity, startMillis, flags);
menu.setHeaderTitle(title);
int numSelectedEvents = mSelectedEvents.size();
if (mNumDays == 1) {
// Day view.
// If there is a selected event, then allow it to be viewed and
// edited.
if (numSelectedEvents >= 1) {
item = menu.add(0, MenuHelper.MENU_EVENT_VIEW, 0, R.string.event_view);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_info_details);
if (isEventEditable(mContext, mSelectedEvent)) {
item = menu.add(0, MenuHelper.MENU_EVENT_EDIT, 0, R.string.event_edit);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_edit);
item.setAlphabeticShortcut('e");
item = menu.add(0, MenuHelper.MENU_EVENT_DELETE, 0, R.string.event_delete);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_delete);
}
item = menu.add(0, MenuHelper.MENU_EVENT_CREATE, 0, R.string.event_create);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_add);
item.setAlphabeticShortcut('n");
} else {
// Otherwise, if the user long-pressed on a blank hour, allow
// them to create an event. They can also do this by tapping.
item = menu.add(0, MenuHelper.MENU_EVENT_CREATE, 0, R.string.event_create);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_add);
item.setAlphabeticShortcut('n");
}
} else {
// Week view.
// If there is a selected event, then allow it to be viewed and
// edited.
if (numSelectedEvents >= 1) {
item = menu.add(0, MenuHelper.MENU_EVENT_VIEW, 0, R.string.event_view);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_info_details);
if (isEventEditable(mContext, mSelectedEvent)) {
item = menu.add(0, MenuHelper.MENU_EVENT_EDIT, 0, R.string.event_edit);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_edit);
item.setAlphabeticShortcut('e");
item = menu.add(0, MenuHelper.MENU_EVENT_DELETE, 0, R.string.event_delete);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_delete);
}
item = menu.add(0, MenuHelper.MENU_EVENT_CREATE, 0, R.string.event_create);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_add);
item.setAlphabeticShortcut('n");
item = menu.add(0, MenuHelper.MENU_DAY, 0, R.string.show_day_view);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_day);
item.setAlphabeticShortcut('d");
item = menu.add(0, MenuHelper.MENU_AGENDA, 0, R.string.show_agenda_view);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_agenda);
item.setAlphabeticShortcut('a");
} else {
// No events are selected
item = menu.add(0, MenuHelper.MENU_EVENT_CREATE, 0, R.string.event_create);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_add);
item.setAlphabeticShortcut('n");
item = menu.add(0, MenuHelper.MENU_DAY, 0, R.string.show_day_view);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_day);
item.setAlphabeticShortcut('d");
item = menu.add(0, MenuHelper.MENU_AGENDA, 0, R.string.show_agenda_view);
item.setOnMenuItemClickListener(mContextMenuHandler);
item.setIcon(android.R.drawable.ic_menu_agenda);
item.setAlphabeticShortcut('a");
}
}
mPopup.dismiss();
| protected void | onDetachedFromWindow()
cleanup();
if (mBitmap != null) {
mBitmap.recycle();
mBitmap = null;
}
super.onDetachedFromWindow();
| protected void | onDraw(android.graphics.Canvas canvas)
if (mRemeasure) {
remeasure(getWidth(), getHeight());
mRemeasure = false;
}
if (mRedrawScreen && mCanvas != null) {
doDraw(mCanvas);
mRedrawScreen = false;
}
if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
canvas.save();
if (mViewStartX > 0) {
canvas.translate(mViewWidth - mViewStartX, 0);
} else {
canvas.translate(-(mViewWidth + mViewStartX), 0);
}
CalendarView nextView = mParentActivity.getNextView();
// Prevent infinite recursive calls to onDraw().
nextView.mTouchMode = TOUCH_MODE_INITIAL_STATE;
nextView.onDraw(canvas);
canvas.restore();
canvas.save();
canvas.translate(-mViewStartX, 0);
}
if (mBitmap != null) {
drawCalendarView(canvas);
}
// Draw the fixed areas (that don't scroll) directly to the canvas.
drawAfterScroll(canvas);
mComputeSelectedEvents = false;
if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
canvas.restore();
}
| public boolean | onKeyDown(int keyCode, android.view.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;
mScrolling = false;
boolean redraw;
int selectionDay = mSelectionDay;
switch (keyCode) {
case KeyEvent.KEYCODE_DEL:
// Delete the selected event, if any
Event selectedEvent = mSelectedEvent;
if (selectedEvent == null) {
return false;
}
mPopup.dismiss();
long begin = selectedEvent.startMillis;
long end = selectedEvent.endMillis;
long id = selectedEvent.id;
mDeleteEventHelper.delete(begin, end, id, -1);
return true;
case KeyEvent.KEYCODE_ENTER:
switchViews(true /* trackball or keyboard */);
return true;
case KeyEvent.KEYCODE_BACK:
mPopup.dismiss();
mParentActivity.finish();
return true;
case KeyEvent.KEYCODE_DPAD_LEFT:
if (mSelectedEvent != null) {
mSelectedEvent = mSelectedEvent.nextLeft;
}
if (mSelectedEvent == null) {
selectionDay -= 1;
}
redraw = true;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (mSelectedEvent != null) {
mSelectedEvent = mSelectedEvent.nextRight;
}
if (mSelectedEvent == null) {
selectionDay += 1;
}
redraw = true;
break;
case KeyEvent.KEYCODE_DPAD_UP:
if (mSelectedEvent != null) {
mSelectedEvent = mSelectedEvent.nextUp;
}
if (mSelectedEvent == null) {
if (!mSelectionAllDay) {
mSelectionHour -= 1;
adjustHourSelection();
mSelectedEvents.clear();
mComputeSelectedEvents = true;
}
}
redraw = true;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
if (mSelectedEvent != null) {
mSelectedEvent = mSelectedEvent.nextDown;
}
if (mSelectedEvent == null) {
if (mSelectionAllDay) {
mSelectionAllDay = false;
} else {
mSelectionHour++;
adjustHourSelection();
mSelectedEvents.clear();
mComputeSelectedEvents = true;
}
}
redraw = true;
break;
default:
return super.onKeyDown(keyCode, event);
}
if ((selectionDay < mFirstJulianDay) || (selectionDay > mLastJulianDay)) {
boolean forward;
CalendarView view = mParentActivity.getNextView();
Time date = view.mBaseDate;
date.set(mBaseDate);
if (selectionDay < mFirstJulianDay) {
date.monthDay -= mNumDays;
forward = false;
} else {
date.monthDay += mNumDays;
forward = true;
}
date.normalize(true /* ignore isDst */);
view.mSelectionDay = selectionDay;
initView(view);
mTitleTextView.setText(view.mDateRange);
mParentActivity.switchViews(forward, 0, 0);
return true;
}
mSelectionDay = selectionDay;
mSelectedEvents.clear();
mComputeSelectedEvents = true;
if (redraw) {
mRedrawScreen = true;
invalidate();
return true;
}
return super.onKeyDown(keyCode, event);
| public boolean | onKeyUp(int keyCode, android.view.KeyEvent event)
mScrolling = false;
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()) {
switchViews(true /* trackball */);
} else {
mSelectionMode = SELECTION_LONGPRESS;
mRedrawScreen = true;
invalidate();
performLongClick();
}
break;
}
return super.onKeyUp(keyCode, event);
| protected void | onSizeChanged(int width, int height, int oldw, int oldh)
mViewWidth = width;
mViewHeight = height;
int gridAreaWidth = width - mHoursWidth;
mCellWidth = (gridAreaWidth - (mNumDays * DAY_GAP)) / mNumDays;
Paint p = new Paint();
p.setTextSize(NORMAL_FONT_SIZE);
int bannerTextHeight = (int) Math.abs(p.ascent());
p.setTextSize(HOURS_FONT_SIZE);
mHoursTextHeight = (int) Math.abs(p.ascent());
p.setTextSize(EVENT_TEXT_FONT_SIZE);
float ascent = -p.ascent();
mEventTextAscent = (int) Math.ceil(ascent);
float totalHeight = ascent + p.descent();
mEventTextHeight = (int) Math.ceil(totalHeight);
if (mNumDays > 1) {
mBannerPlusMargin = bannerTextHeight + 14;
} else {
mBannerPlusMargin = 0;
}
remeasure(width, height);
| public boolean | onTouchEvent(android.view.MotionEvent ev)
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mParentActivity.mGestureDetector.onTouchEvent(ev);
return true;
case MotionEvent.ACTION_MOVE:
mParentActivity.mGestureDetector.onTouchEvent(ev);
return true;
case MotionEvent.ACTION_UP:
mParentActivity.mGestureDetector.onTouchEvent(ev);
if (mOnFlingCalled) {
return true;
}
if ((mTouchMode & TOUCH_MODE_HSCROLL) != 0) {
mTouchMode = TOUCH_MODE_INITIAL_STATE;
if (Math.abs(mViewStartX) > HORIZONTAL_SCROLL_THRESHOLD) {
// The user has gone beyond the threshold so switch views
mParentActivity.switchViews(mViewStartX > 0, mViewStartX, mViewWidth);
mViewStartX = 0;
return true;
} else {
// Not beyond the threshold so invalidate which will cause
// the view to snap back. Also call recalc() to ensure
// that we have the correct starting date and title.
recalc();
mTitleTextView.setText(mDateRange);
invalidate();
mViewStartX = 0;
}
}
// If we were scrolling, then reset the selected hour so that it
// is visible.
if (mScrolling) {
mScrolling = false;
resetSelectedHour();
mRedrawScreen = true;
invalidate();
}
return true;
// This case isn't expected to happen.
case MotionEvent.ACTION_CANCEL:
mParentActivity.mGestureDetector.onTouchEvent(ev);
mScrolling = false;
resetSelectedHour();
return true;
default:
if (mParentActivity.mGestureDetector.onTouchEvent(ev)) {
return true;
}
return super.onTouchEvent(ev);
}
| private void | recalc()
// Set the base date to the beginning of the week if we are displaying
// 7 days at a time.
if (mNumDays == 7) {
int dayOfWeek = mBaseDate.weekDay;
int diff = dayOfWeek - mStartDay;
if (diff != 0) {
if (diff < 0) {
diff += 7;
}
mBaseDate.monthDay -= diff;
mBaseDate.normalize(true /* ignore isDst */);
}
}
final long start = mBaseDate.toMillis(false /* use isDst */);
long end = start;
mFirstJulianDay = Time.getJulianDay(start, mBaseDate.gmtoff);
mLastJulianDay = mFirstJulianDay + mNumDays - 1;
mMonthLength = mBaseDate.getActualMaximum(Time.MONTH_DAY);
mFirstDate = mBaseDate.monthDay;
int flags = DateUtils.FORMAT_SHOW_YEAR;
if (DateFormat.is24HourFormat(mContext)) {
flags |= DateUtils.FORMAT_24HOUR;
}
if (mNumDays > 1) {
mBaseDate.monthDay += mNumDays - 1;
end = mBaseDate.toMillis(true /* ignore isDst */);
mBaseDate.monthDay -= mNumDays - 1;
flags |= DateUtils.FORMAT_NO_MONTH_DAY;
} else {
flags |= DateUtils.FORMAT_SHOW_WEEKDAY
| DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
}
mDateRange = DateUtils.formatDateRange(mParentActivity, start, end, flags);
// Do not set the title here because this is called when executing
// initNextView() to prepare the Day view when sliding the finger
// horizontally but we don't always want to change the title. And
// if we change the title here and then change it back in the caller
// then we get an annoying flicker.
| void | reloadEvents()
// Protect against this being called before this view has been
// initialized.
if (mParentActivity == null) {
return;
}
mSelectedEvent = null;
mPrevSelectedEvent = null;
mSelectedEvents.clear();
// The start date is the beginning of the week at 12am
Time weekStart = new Time();
weekStart.set(mBaseDate);
weekStart.hour = 0;
weekStart.minute = 0;
weekStart.second = 0;
long millis = weekStart.normalize(true /* ignore isDst */);
// Avoid reloading events unnecessarily.
if (millis == mLastReloadMillis) {
return;
}
mLastReloadMillis = millis;
// load events in the background
mParentActivity.startProgressSpinner();
final ArrayList<Event> events = new ArrayList<Event>();
mEventLoader.loadEventsInBackground(mNumDays, events, millis, new Runnable() {
public void run() {
mEvents = events;
mRemeasure = true;
mRedrawScreen = true;
mComputeSelectedEvents = true;
recalc();
mParentActivity.stopProgressSpinner();
invalidate();
}
}, mCancelCallback);
| private void | remeasure(int width, int height)
// First, clear the array of earliest start times, and the array
// indicating presence of an all-day event.
for (int day = 0; day < mNumDays; day++) {
mEarliestStartHour[day] = 25; // some big number
mHasAllDayEvent[day] = false;
}
// Compute the space needed for the all-day events, if any.
// Make a pass over all the events, and keep track of the maximum
// number of all-day events in any one day. Also, keep track of
// the earliest event in each day.
int maxAllDayEvents = 0;
ArrayList<Event> events = mEvents;
int len = events.size();
for (int ii = 0; ii < len; ii++) {
Event event = events.get(ii);
if (event.startDay > mLastJulianDay || event.endDay < mFirstJulianDay)
continue;
if (event.allDay) {
int max = event.getColumn() + 1;
if (maxAllDayEvents < max) {
maxAllDayEvents = max;
}
int daynum = event.startDay - mFirstJulianDay;
int durationDays = event.endDay - event.startDay + 1;
if (daynum < 0) {
durationDays += daynum;
daynum = 0;
}
if (daynum + durationDays > mNumDays) {
durationDays = mNumDays - daynum;
}
for (int day = daynum; durationDays > 0; day++, durationDays--) {
mHasAllDayEvent[day] = true;
}
} else {
int daynum = event.startDay - mFirstJulianDay;
int hour = event.startTime / 60;
if (daynum >= 0 && hour < mEarliestStartHour[daynum]) {
mEarliestStartHour[daynum] = hour;
}
// Also check the end hour in case the event spans more than
// one day.
daynum = event.endDay - mFirstJulianDay;
hour = event.endTime / 60;
if (daynum < mNumDays && hour < mEarliestStartHour[daynum]) {
mEarliestStartHour[daynum] = hour;
}
}
}
mMaxAllDayEvents = maxAllDayEvents;
mFirstCell = mBannerPlusMargin;
int allDayHeight = 0;
if (maxAllDayEvents > 0) {
// If there is at most one all-day event per day, then use less
// space (but more than the space for a single event).
if (maxAllDayEvents == 1) {
allDayHeight = SINGLE_ALLDAY_HEIGHT;
} else {
// Allow the all-day area to grow in height depending on the
// number of all-day events we need to show, up to a limit.
allDayHeight = maxAllDayEvents * MAX_ALLDAY_EVENT_HEIGHT;
if (allDayHeight > MAX_ALLDAY_HEIGHT) {
allDayHeight = MAX_ALLDAY_HEIGHT;
}
}
mFirstCell = mBannerPlusMargin + allDayHeight + ALLDAY_TOP_MARGIN;
} else {
mSelectionAllDay = false;
}
mAllDayHeight = allDayHeight;
mGridAreaHeight = height - mFirstCell;
mCellHeight = (mGridAreaHeight - ((mNumHours + 1) * HOUR_GAP)) / mNumHours;
int usedGridAreaHeight = (mCellHeight + HOUR_GAP) * mNumHours + HOUR_GAP;
int bottomSpace = mGridAreaHeight - usedGridAreaHeight;
mEventGeometry.setHourHeight(mCellHeight);
// Create an off-screen bitmap that we can draw into.
mBitmapHeight = HOUR_GAP + 24 * (mCellHeight + HOUR_GAP) + bottomSpace;
if ((mBitmap == null || mBitmap.getHeight() < mBitmapHeight) && width > 0 &&
mBitmapHeight > 0) {
if (mBitmap != null) {
mBitmap.recycle();
}
mBitmap = Bitmap.createBitmap(width, mBitmapHeight, Bitmap.Config.RGB_565);
mCanvas = new Canvas(mBitmap);
}
mMaxViewStartY = mBitmapHeight - mGridAreaHeight;
if (mFirstHour == -1) {
initFirstHour();
mFirstHourOffset = 0;
}
// When we change the base date, the number of all-day events may
// change and that changes the cell height. When we switch dates,
// we use the mFirstHourOffset from the previous view, but that may
// be too large for the new view if the cell height is smaller.
if (mFirstHourOffset >= mCellHeight + HOUR_GAP) {
mFirstHourOffset = mCellHeight + HOUR_GAP - 1;
}
mViewStartY = mFirstHour * (mCellHeight + HOUR_GAP) - mFirstHourOffset;
int eventAreaWidth = mNumDays * (mCellWidth + DAY_GAP);
mPopup.dismiss();
mPopup.setWidth(eventAreaWidth - 20);
mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
| private void | resetSelectedHour()
if (mSelectionHour < mFirstHour + 1) {
mSelectionHour = mFirstHour + 1;
mSelectedEvent = null;
mSelectedEvents.clear();
mComputeSelectedEvents = true;
} else if (mSelectionHour > mFirstHour + mNumHours - 3) {
mSelectionHour = mFirstHour + mNumHours - 3;
mSelectedEvent = null;
mSelectedEvents.clear();
mComputeSelectedEvents = true;
}
| private void | saveSelectionPosition(float left, float top, float right, float bottom)
mPrevBox.left = (int) left;
mPrevBox.right = (int) right;
mPrevBox.top = (int) top;
mPrevBox.bottom = (int) bottom;
| void | setDetailedView(java.lang.String detailedView)
mDetailedView = detailedView;
| public void | setSelectedDay(android.text.format.Time time)
mBaseDate.set(time);
mSelectionHour = mBaseDate.hour;
mSelectedEvent = null;
mPrevSelectedEvent = null;
long millis = mBaseDate.toMillis(false /* use isDst */);
mSelectionDay = Time.getJulianDay(millis, mBaseDate.gmtoff);
mSelectedEvents.clear();
mComputeSelectedEvents = true;
// Force a recalculation of the first visible hour
mFirstHour = -1;
recalc();
mTitleTextView.setText(mDateRange);
// Force a redraw of the selection box.
mSelectionMode = SELECTION_SELECTED;
mRedrawScreen = true;
mRemeasure = true;
invalidate();
| private boolean | setSelectionFromPosition(int x, int y)Sets mSelectionDay and mSelectionHour based on the (x,y) touch position.
If the touch position is not within the displayed grid, then this
method returns false.
if (x < mHoursWidth) {
return false;
}
int day = (x - mHoursWidth) / (mCellWidth + DAY_GAP);
if (day >= mNumDays) {
day = mNumDays - 1;
}
day += mFirstJulianDay;
int hour;
if (y < mFirstCell + mFirstHourOffset) {
mSelectionAllDay = true;
} else {
hour = (y - mFirstCell - mFirstHourOffset) / (mCellHeight + HOUR_GAP);
hour += mFirstHour;
mSelectionHour = hour;
mSelectionAllDay = false;
}
mSelectionDay = day;
findSelectedEvent(x, y);
// Log.i("Cal", "setSelectionFromPosition( " + x + ", " + y + " ) day: " + day
// + " hour: " + hour
// + " mFirstCell: " + mFirstCell + " mFirstHourOffset: " + mFirstHourOffset);
// if (mSelectedEvent != null) {
// Log.i("Cal", " num events: " + mSelectedEvents.size() + " event: " + mSelectedEvent.title);
// for (Event ev : mSelectedEvents) {
// int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL
// | DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
// String timeRange = formatDateRange(mParentActivity,
// ev.startMillis, ev.endMillis, flags);
//
// Log.i("Cal", " " + timeRange + " " + ev.title);
// }
// }
return true;
| private void | switchViews(boolean trackBallSelection)Switch to another view based on what was selected (an event or a free
slot) and how it was selected (by touch or by trackball).
Event selectedEvent = mSelectedEvent;
mPopup.dismiss();
if (mNumDays > 1) {
// This is the Week view.
// With touch, we always switch to Day/Agenda View
// With track ball, if we selected a free slot, then create an event.
// If we selected a specific event, switch to EventInfo view.
if (trackBallSelection) {
if (selectedEvent == null) {
// Switch to the EditEvent view
long startMillis = getSelectedTimeInMillis();
long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(mContext, EditEvent.class.getName());
intent.putExtra(EVENT_BEGIN_TIME, startMillis);
intent.putExtra(EVENT_END_TIME, endMillis);
mParentActivity.startActivity(intent);
} else {
// Switch to the EventInfo view
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI,
selectedEvent.id);
intent.setData(eventUri);
intent.setClassName(mContext, EventInfoActivity.class.getName());
intent.putExtra(EVENT_BEGIN_TIME, selectedEvent.startMillis);
intent.putExtra(EVENT_END_TIME, selectedEvent.endMillis);
mParentActivity.startActivity(intent);
}
} else {
// This was a touch selection. If the touch selected a single
// unambiguous event, then view that event. Otherwise go to
// Day/Agenda view.
if (mSelectedEvents.size() == 1) {
// Switch to the EventInfo view
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI,
selectedEvent.id);
intent.setData(eventUri);
intent.setClassName(mContext, EventInfoActivity.class.getName());
intent.putExtra(EVENT_BEGIN_TIME, selectedEvent.startMillis);
intent.putExtra(EVENT_END_TIME, selectedEvent.endMillis);
mParentActivity.startActivity(intent);
} else {
// Switch to the Day/Agenda view.
long millis = getSelectedTimeInMillis();
MenuHelper.switchTo(mParentActivity, mDetailedView, millis);
mParentActivity.finish();
}
}
} else {
// This is the Day view.
// If we selected a free slot, then create an event.
// If we selected an event, then go to the EventInfo view.
if (selectedEvent == null) {
// Switch to the EditEvent view
long startMillis = getSelectedTimeInMillis();
long endMillis = startMillis + DateUtils.HOUR_IN_MILLIS;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClassName(mContext, EditEvent.class.getName());
intent.putExtra(EVENT_BEGIN_TIME, startMillis);
intent.putExtra(EVENT_END_TIME, endMillis);
mParentActivity.startActivity(intent);
} else {
// Switch to the EventInfo view
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, selectedEvent.id);
intent.setData(eventUri);
intent.setClassName(mContext, EventInfoActivity.class.getName());
intent.putExtra(EVENT_BEGIN_TIME, selectedEvent.startMillis);
intent.putExtra(EVENT_END_TIME, selectedEvent.endMillis);
mParentActivity.startActivity(intent);
}
}
| private void | updateEventDetails()
if (mSelectedEvent == null || mSelectionMode == SELECTION_HIDDEN
|| mSelectionMode == SELECTION_LONGPRESS) {
mPopup.dismiss();
return;
}
// Remove any outstanding callbacks to dismiss the popup.
getHandler().removeCallbacks(mDismissPopup);
Event event = mSelectedEvent;
TextView titleView = (TextView) mPopupView.findViewById(R.id.event_title);
titleView.setText(event.title);
ImageView imageView = (ImageView) mPopupView.findViewById(R.id.reminder_icon);
imageView.setVisibility(event.hasAlarm ? View.VISIBLE : View.GONE);
imageView = (ImageView) mPopupView.findViewById(R.id.repeat_icon);
imageView.setVisibility(event.isRepeating ? View.VISIBLE : View.GONE);
int flags;
if (event.allDay) {
flags = DateUtils.FORMAT_UTC | DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL;
} else {
flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_ALL
| DateUtils.FORMAT_CAP_NOON_MIDNIGHT;
}
if (DateFormat.is24HourFormat(mContext)) {
flags |= DateUtils.FORMAT_24HOUR;
}
String timeRange = DateUtils.formatDateRange(mParentActivity,
event.startMillis, event.endMillis, flags);
TextView timeView = (TextView) mPopupView.findViewById(R.id.time);
timeView.setText(timeRange);
TextView whereView = (TextView) mPopupView.findViewById(R.id.where);
final boolean empty = TextUtils.isEmpty(event.location);
whereView.setVisibility(empty ? View.GONE : View.VISIBLE);
if (!empty) whereView.setText(event.location);
mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.LEFT, mHoursWidth, 5);
postDelayed(mDismissPopup, POPUP_DISMISS_DELAY);
|
|