1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.calendar; 18 19import com.android.calendar.CalendarController.EventInfo; 20import com.android.calendar.CalendarController.EventType; 21 22import android.app.Fragment; 23import android.content.Context; 24import android.os.Bundle; 25import android.text.format.Time; 26import android.view.LayoutInflater; 27import android.view.View; 28import android.view.ViewGroup; 29import android.view.ViewGroup.LayoutParams; 30import android.view.animation.Animation; 31import android.view.animation.AnimationUtils; 32import android.widget.ProgressBar; 33import android.widget.ViewSwitcher; 34import android.widget.ViewSwitcher.ViewFactory; 35 36/** 37 * This is the base class for Day and Week Activities. 38 */ 39public class DayFragment extends Fragment implements CalendarController.EventHandler, ViewFactory { 40 /** 41 * The view id used for all the views we create. It's OK to have all child 42 * views have the same ID. This ID is used to pick which view receives 43 * focus when a view hierarchy is saved / restore 44 */ 45 private static final int VIEW_ID = 1; 46 47 protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time"; 48 49 protected ProgressBar mProgressBar; 50 protected ViewSwitcher mViewSwitcher; 51 protected Animation mInAnimationForward; 52 protected Animation mOutAnimationForward; 53 protected Animation mInAnimationBackward; 54 protected Animation mOutAnimationBackward; 55 EventLoader mEventLoader; 56 57 Time mSelectedDay = new Time(); 58 59 private final Runnable mTZUpdater = new Runnable() { 60 @Override 61 public void run() { 62 if (!DayFragment.this.isAdded()) { 63 return; 64 } 65 String tz = Utils.getTimeZone(getActivity(), mTZUpdater); 66 mSelectedDay.timezone = tz; 67 mSelectedDay.normalize(true); 68 } 69 }; 70 71 private int mNumDays; 72 73 public DayFragment() { 74 mSelectedDay.setToNow(); 75 } 76 77 public DayFragment(long timeMillis, int numOfDays) { 78 mNumDays = numOfDays; 79 if (timeMillis == 0) { 80 mSelectedDay.setToNow(); 81 } else { 82 mSelectedDay.set(timeMillis); 83 } 84 } 85 86 @Override 87 public void onCreate(Bundle icicle) { 88 super.onCreate(icicle); 89 90 Context context = getActivity(); 91 92 mInAnimationForward = AnimationUtils.loadAnimation(context, R.anim.slide_left_in); 93 mOutAnimationForward = AnimationUtils.loadAnimation(context, R.anim.slide_left_out); 94 mInAnimationBackward = AnimationUtils.loadAnimation(context, R.anim.slide_right_in); 95 mOutAnimationBackward = AnimationUtils.loadAnimation(context, R.anim.slide_right_out); 96 97 mEventLoader = new EventLoader(context); 98 } 99 100 @Override 101 public View onCreateView(LayoutInflater inflater, ViewGroup container, 102 Bundle savedInstanceState) { 103 View v = inflater.inflate(R.layout.day_activity, null); 104 105 mViewSwitcher = (ViewSwitcher) v.findViewById(R.id.switcher); 106 mViewSwitcher.setFactory(this); 107 mViewSwitcher.getCurrentView().requestFocus(); 108 ((DayView) mViewSwitcher.getCurrentView()).updateTitle(); 109 110 return v; 111 } 112 113 public View makeView() { 114 mTZUpdater.run(); 115 DayView view = new DayView(getActivity(), CalendarController 116 .getInstance(getActivity()), mViewSwitcher, mEventLoader, mNumDays); 117 view.setId(VIEW_ID); 118 view.setLayoutParams(new ViewSwitcher.LayoutParams( 119 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 120 view.setSelected(mSelectedDay, false, false); 121 return view; 122 } 123 124 @Override 125 public void onResume() { 126 super.onResume(); 127 mEventLoader.startBackgroundThread(); 128 mTZUpdater.run(); 129 eventsChanged(); 130 DayView view = (DayView) mViewSwitcher.getCurrentView(); 131 view.handleOnResume(); 132 view.restartCurrentTimeUpdates(); 133 134 view = (DayView) mViewSwitcher.getNextView(); 135 view.handleOnResume(); 136 view.restartCurrentTimeUpdates(); 137 } 138 139 @Override 140 public void onSaveInstanceState(Bundle outState) { 141 super.onSaveInstanceState(outState); 142 143 long time = getSelectedTimeInMillis(); 144 if (time != -1) { 145 outState.putLong(BUNDLE_KEY_RESTORE_TIME, time); 146 } 147 } 148 149 @Override 150 public void onPause() { 151 super.onPause(); 152 DayView view = (DayView) mViewSwitcher.getCurrentView(); 153 view.cleanup(); 154 view = (DayView) mViewSwitcher.getNextView(); 155 view.cleanup(); 156 mEventLoader.stopBackgroundThread(); 157 158 // Stop events cross-fade animation 159 view.stopEventsAnimation(); 160 ((DayView) mViewSwitcher.getNextView()).stopEventsAnimation(); 161 } 162 163 void startProgressSpinner() { 164 // start the progress spinner 165 mProgressBar.setVisibility(View.VISIBLE); 166 } 167 168 void stopProgressSpinner() { 169 // stop the progress spinner 170 mProgressBar.setVisibility(View.GONE); 171 } 172 173 private void goTo(Time goToTime, boolean ignoreTime, boolean animateToday) { 174 if (mViewSwitcher == null) { 175 // The view hasn't been set yet. Just save the time and use it later. 176 mSelectedDay.set(goToTime); 177 return; 178 } 179 180 DayView currentView = (DayView) mViewSwitcher.getCurrentView(); 181 182 // How does goTo time compared to what's already displaying? 183 int diff = currentView.compareToVisibleTimeRange(goToTime); 184 185 if (diff == 0) { 186 // In visible range. No need to switch view 187 currentView.setSelected(goToTime, ignoreTime, animateToday); 188 } else { 189 // Figure out which way to animate 190 if (diff > 0) { 191 mViewSwitcher.setInAnimation(mInAnimationForward); 192 mViewSwitcher.setOutAnimation(mOutAnimationForward); 193 } else { 194 mViewSwitcher.setInAnimation(mInAnimationBackward); 195 mViewSwitcher.setOutAnimation(mOutAnimationBackward); 196 } 197 198 DayView next = (DayView) mViewSwitcher.getNextView(); 199 if (ignoreTime) { 200 next.setFirstVisibleHour(currentView.getFirstVisibleHour()); 201 } 202 203 next.setSelected(goToTime, ignoreTime, animateToday); 204 next.reloadEvents(); 205 mViewSwitcher.showNext(); 206 next.requestFocus(); 207 next.updateTitle(); 208 next.restartCurrentTimeUpdates(); 209 } 210 } 211 212 /** 213 * Returns the selected time in milliseconds. The milliseconds are measured 214 * in UTC milliseconds from the epoch and uniquely specifies any selectable 215 * time. 216 * 217 * @return the selected time in milliseconds 218 */ 219 public long getSelectedTimeInMillis() { 220 if (mViewSwitcher == null) { 221 return -1; 222 } 223 DayView view = (DayView) mViewSwitcher.getCurrentView(); 224 if (view == null) { 225 return -1; 226 } 227 return view.getSelectedTimeInMillis(); 228 } 229 230 public void eventsChanged() { 231 if (mViewSwitcher == null) { 232 return; 233 } 234 DayView view = (DayView) mViewSwitcher.getCurrentView(); 235 view.clearCachedEvents(); 236 view.reloadEvents(); 237 238 view = (DayView) mViewSwitcher.getNextView(); 239 view.clearCachedEvents(); 240 } 241 242 Event getSelectedEvent() { 243 DayView view = (DayView) mViewSwitcher.getCurrentView(); 244 return view.getSelectedEvent(); 245 } 246 247 boolean isEventSelected() { 248 DayView view = (DayView) mViewSwitcher.getCurrentView(); 249 return view.isEventSelected(); 250 } 251 252 Event getNewEvent() { 253 DayView view = (DayView) mViewSwitcher.getCurrentView(); 254 return view.getNewEvent(); 255 } 256 257 public DayView getNextView() { 258 return (DayView) mViewSwitcher.getNextView(); 259 } 260 261 public long getSupportedEventTypes() { 262 return EventType.GO_TO | EventType.EVENTS_CHANGED; 263 } 264 265 public void handleEvent(EventInfo msg) { 266 if (msg.eventType == EventType.GO_TO) { 267// TODO support a range of time 268// TODO support event_id 269// TODO support select message 270 goTo(msg.selectedTime, (msg.extraLong & CalendarController.EXTRA_GOTO_DATE) != 0, 271 (msg.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0); 272 } else if (msg.eventType == EventType.EVENTS_CHANGED) { 273 eventsChanged(); 274 } 275 } 276} 277