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 17 package com.android.calendar; 18 19 import com.android.calendar.CalendarController.EventInfo; 20 import com.android.calendar.CalendarController.EventType; 21 22 import android.app.Fragment; 23 import android.content.Context; 24 import android.os.Bundle; 25 import android.text.format.Time; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.view.ViewGroup.LayoutParams; 30 import android.view.animation.Animation; 31 import android.view.animation.AnimationUtils; 32 import android.widget.ProgressBar; 33 import android.widget.ViewSwitcher; 34 import android.widget.ViewSwitcher.ViewFactory; 35 36 /** 37 * This is the base class for Day and Week Activities. 38 */ 39 public 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 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 159 void startProgressSpinner() { 160 // start the progress spinner 161 mProgressBar.setVisibility(View.VISIBLE); 162 } 163 164 void stopProgressSpinner() { 165 // stop the progress spinner 166 mProgressBar.setVisibility(View.GONE); 167 } 168 169 private void goTo(Time goToTime, boolean ignoreTime, boolean animateToday) { 170 if (mViewSwitcher == null) { 171 // The view hasn't been set yet. Just save the time and use it later. 172 mSelectedDay.set(goToTime); 173 return; 174 } 175 176 DayView currentView = (DayView) mViewSwitcher.getCurrentView(); 177 178 // How does goTo time compared to what's already displaying? 179 int diff = currentView.compareToVisibleTimeRange(goToTime); 180 181 if (diff == 0) { 182 // In visible range. No need to switch view 183 currentView.setSelected(goToTime, ignoreTime, animateToday); 184 } else { 185 // Figure out which way to animate 186 if (diff > 0) { 187 mViewSwitcher.setInAnimation(mInAnimationForward); 188 mViewSwitcher.setOutAnimation(mOutAnimationForward); 189 } else { 190 mViewSwitcher.setInAnimation(mInAnimationBackward); 191 mViewSwitcher.setOutAnimation(mOutAnimationBackward); 192 } 193 194 DayView next = (DayView) mViewSwitcher.getNextView(); 195 if (ignoreTime) { 196 next.setFirstVisibleHour(currentView.getFirstVisibleHour()); 197 } 198 199 next.setSelected(goToTime, ignoreTime, animateToday); 200 next.reloadEvents(); 201 mViewSwitcher.showNext(); 202 next.requestFocus(); 203 next.updateTitle(); 204 next.restartCurrentTimeUpdates(); 205 } 206 } 207 208 /** 209 * Returns the selected time in milliseconds. The milliseconds are measured 210 * in UTC milliseconds from the epoch and uniquely specifies any selectable 211 * time. 212 * 213 * @return the selected time in milliseconds 214 */ 215 public long getSelectedTimeInMillis() { 216 if (mViewSwitcher == null) { 217 return -1; 218 } 219 DayView view = (DayView) mViewSwitcher.getCurrentView(); 220 if (view == null) { 221 return -1; 222 } 223 return view.getSelectedTimeInMillis(); 224 } 225 226 public void eventsChanged() { 227 if (mViewSwitcher == null) { 228 return; 229 } 230 DayView view = (DayView) mViewSwitcher.getCurrentView(); 231 view.clearCachedEvents(); 232 view.reloadEvents(); 233 234 view = (DayView) mViewSwitcher.getNextView(); 235 view.clearCachedEvents(); 236 } 237 238 Event getSelectedEvent() { 239 DayView view = (DayView) mViewSwitcher.getCurrentView(); 240 return view.getSelectedEvent(); 241 } 242 243 boolean isEventSelected() { 244 DayView view = (DayView) mViewSwitcher.getCurrentView(); 245 return view.isEventSelected(); 246 } 247 248 Event getNewEvent() { 249 DayView view = (DayView) mViewSwitcher.getCurrentView(); 250 return view.getNewEvent(); 251 } 252 253 public DayView getNextView() { 254 return (DayView) mViewSwitcher.getNextView(); 255 } 256 257 public long getSupportedEventTypes() { 258 return EventType.GO_TO | EventType.EVENTS_CHANGED; 259 } 260 261 public void handleEvent(EventInfo msg) { 262 if (msg.eventType == EventType.GO_TO) { 263 // TODO support a range of time 264 // TODO support event_id 265 // TODO support select message 266 goTo(msg.selectedTime, (msg.extraLong & CalendarController.EXTRA_GOTO_DATE) != 0, 267 (msg.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0); 268 } else if (msg.eventType == EventType.EVENTS_CHANGED) { 269 eventsChanged(); 270 } 271 } 272 } 273