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 
144     @Override
onPause()145     public void onPause() {
146         super.onPause();
147         DayView view = (DayView) mViewSwitcher.getCurrentView();
148         view.cleanup();
149         view = (DayView) mViewSwitcher.getNextView();
150         view.cleanup();
151         mEventLoader.stopBackgroundThread();
152 
153         // Stop events cross-fade animation
154         view.stopEventsAnimation();
155         ((DayView) mViewSwitcher.getNextView()).stopEventsAnimation();
156     }
157 
startProgressSpinner()158     void startProgressSpinner() {
159         // start the progress spinner
160         mProgressBar.setVisibility(View.VISIBLE);
161     }
162 
stopProgressSpinner()163     void stopProgressSpinner() {
164         // stop the progress spinner
165         mProgressBar.setVisibility(View.GONE);
166     }
167 
goTo(Time goToTime, boolean ignoreTime, boolean animateToday)168     private void goTo(Time goToTime, boolean ignoreTime, boolean animateToday) {
169         if (mViewSwitcher == null) {
170             // The view hasn't been set yet. Just save the time and use it later.
171             mSelectedDay.set(goToTime);
172             return;
173         }
174 
175         DayView currentView = (DayView) mViewSwitcher.getCurrentView();
176 
177         // How does goTo time compared to what's already displaying?
178         int diff = currentView.compareToVisibleTimeRange(goToTime);
179 
180         if (diff == 0) {
181             // In visible range. No need to switch view
182             currentView.setSelected(goToTime, ignoreTime, animateToday);
183         } else {
184             // Figure out which way to animate
185             if (diff > 0) {
186                 mViewSwitcher.setInAnimation(mInAnimationForward);
187                 mViewSwitcher.setOutAnimation(mOutAnimationForward);
188             } else {
189                 mViewSwitcher.setInAnimation(mInAnimationBackward);
190                 mViewSwitcher.setOutAnimation(mOutAnimationBackward);
191             }
192 
193             DayView next = (DayView) mViewSwitcher.getNextView();
194             if (ignoreTime) {
195                 next.setFirstVisibleHour(currentView.getFirstVisibleHour());
196             }
197 
198             next.setSelected(goToTime, ignoreTime, animateToday);
199             next.reloadEvents();
200             mViewSwitcher.showNext();
201             next.requestFocus();
202             next.updateTitle();
203             next.restartCurrentTimeUpdates();
204         }
205     }
206 
207     /**
208      * Returns the selected time in milliseconds. The milliseconds are measured
209      * in UTC milliseconds from the epoch and uniquely specifies any selectable
210      * time.
211      *
212      * @return the selected time in milliseconds
213      */
getSelectedTimeInMillis()214     public long getSelectedTimeInMillis() {
215         if (mViewSwitcher == null) {
216             return -1;
217         }
218         DayView view = (DayView) mViewSwitcher.getCurrentView();
219         if (view == null) {
220             return -1;
221         }
222         return view.getSelectedTimeInMillis();
223     }
224 
eventsChanged()225     public void eventsChanged() {
226         if (mViewSwitcher == null) {
227             return;
228         }
229         DayView view = (DayView) mViewSwitcher.getCurrentView();
230         view.clearCachedEvents();
231         view.reloadEvents();
232 
233         view = (DayView) mViewSwitcher.getNextView();
234         view.clearCachedEvents();
235     }
236 
getNextView()237     public DayView getNextView() {
238         return (DayView) mViewSwitcher.getNextView();
239     }
240 
getSupportedEventTypes()241     public long getSupportedEventTypes() {
242         return EventType.GO_TO | EventType.EVENTS_CHANGED;
243     }
244 
handleEvent(EventInfo msg)245     public void handleEvent(EventInfo msg) {
246         if (msg.eventType == EventType.GO_TO) {
247 // TODO support a range of time
248 // TODO support event_id
249 // TODO support select message
250             goTo(msg.selectedTime, (msg.extraLong & CalendarController.EXTRA_GOTO_DATE) != 0,
251                     (msg.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0);
252         } else if (msg.eventType == EventType.EVENTS_CHANGED) {
253             eventsChanged();
254         }
255     }
256 }
257