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 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 
DayFragment()73     public DayFragment() {
74         mSelectedDay.setToNow();
75     }
76 
DayFragment(long timeMillis, int numOfDays)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
onCreate(Bundle icicle)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
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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 
makeView()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
onResume()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
onSaveInstanceState(Bundle outState)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
onPause()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 
startProgressSpinner()163     void startProgressSpinner() {
164         // start the progress spinner
165         mProgressBar.setVisibility(View.VISIBLE);
166     }
167 
stopProgressSpinner()168     void stopProgressSpinner() {
169         // stop the progress spinner
170         mProgressBar.setVisibility(View.GONE);
171     }
172 
goTo(Time goToTime, boolean ignoreTime, boolean animateToday)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      */
getSelectedTimeInMillis()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 
eventsChanged()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 
getSelectedEvent()242     Event getSelectedEvent() {
243         DayView view = (DayView) mViewSwitcher.getCurrentView();
244         return view.getSelectedEvent();
245     }
246 
isEventSelected()247     boolean isEventSelected() {
248         DayView view = (DayView) mViewSwitcher.getCurrentView();
249         return view.isEventSelected();
250     }
251 
getNewEvent()252     Event getNewEvent() {
253         DayView view = (DayView) mViewSwitcher.getCurrentView();
254         return view.getNewEvent();
255     }
256 
getNextView()257     public DayView getNextView() {
258         return (DayView) mViewSwitcher.getNextView();
259     }
260 
getSupportedEventTypes()261     public long getSupportedEventTypes() {
262         return EventType.GO_TO | EventType.EVENTS_CHANGED;
263     }
264 
handleEvent(EventInfo msg)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