• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 dalvik.system.VMRuntime;
20 
21 import android.app.Activity;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.database.ContentObserver;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.provider.Calendar;
31 import android.text.format.Time;
32 import android.view.GestureDetector;
33 import android.view.Menu;
34 import android.view.MenuItem;
35 import android.view.MotionEvent;
36 import android.view.View;
37 import android.view.animation.Animation;
38 import android.view.animation.AnimationUtils;
39 import android.view.animation.TranslateAnimation;
40 import android.widget.ProgressBar;
41 import android.widget.ViewSwitcher;
42 
43 /**
44  * This is the base class for Day and Week Activities.
45  */
46 public class CalendarActivity extends Activity implements Navigator {
47 
48     private static final long INITIAL_HEAP_SIZE = 4*1024*1024;
49     private static final long ANIMATION_DURATION = 400;
50 
51     protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
52 
53     private ContentResolver mContentResolver;
54 
55     protected ProgressBar mProgressBar;
56     protected ViewSwitcher mViewSwitcher;
57     protected Animation mInAnimationForward;
58     protected Animation mOutAnimationForward;
59     protected Animation mInAnimationBackward;
60     protected Animation mOutAnimationBackward;
61     EventLoader mEventLoader;
62 
63     Time mSelectedDay;
64 
65     // This gets run if the time zone is updated in the db
66     private Runnable mUpdateTZ = new Runnable() {
67         @Override
68         public void run() {
69             // We want this to keep the same day so we swap the tz
70             mSelectedDay.timezone = Utils.getTimeZone(CalendarActivity.this, this);
71             mSelectedDay.normalize(true);
72         }
73     };
74 
75     /* package */ GestureDetector mGestureDetector;
76 
77     /**
78      * Listens for intent broadcasts
79      */
80     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
81         @Override
82         public void onReceive(Context context, Intent intent) {
83             String action = intent.getAction();
84             if (action.equals(Intent.ACTION_TIME_CHANGED)
85                     || action.equals(Intent.ACTION_DATE_CHANGED)
86                     || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
87                 eventsChanged();
88             }
89         }
90     };
91 
92     // Create an observer so that we can update the views whenever a
93     // Calendar event changes.
94     private ContentObserver mObserver = new ContentObserver(new Handler())
95     {
96         @Override
97         public boolean deliverSelfNotifications() {
98             return true;
99         }
100 
101         @Override
102         public void onChange(boolean selfChange) {
103             eventsChanged();
104         }
105     };
106 
107     @Override
onCreate(Bundle icicle)108     protected void onCreate(Bundle icicle) {
109         super.onCreate(icicle);
110 
111         mSelectedDay = new Time(Utils.getTimeZone(this, mUpdateTZ));
112 
113         // Eliminate extra GCs during startup by setting the initial heap size to 4MB.
114         // TODO: We should restore the old heap size once the activity reaches the idle state
115         VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
116 
117         setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
118         mContentResolver = getContentResolver();
119 
120         mInAnimationForward = AnimationUtils.loadAnimation(this, R.anim.slide_left_in);
121         mOutAnimationForward = AnimationUtils.loadAnimation(this, R.anim.slide_left_out);
122         mInAnimationBackward = AnimationUtils.loadAnimation(this, R.anim.slide_right_in);
123         mOutAnimationBackward = AnimationUtils.loadAnimation(this, R.anim.slide_right_out);
124 
125         mGestureDetector = new GestureDetector(this, new CalendarGestureListener());
126         mEventLoader = new EventLoader(this);
127     }
128 
129     @Override
onRestoreInstanceState(Bundle savedInstanceState)130     protected void onRestoreInstanceState(Bundle savedInstanceState) {
131         super.onRestoreInstanceState(savedInstanceState);
132 
133         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
134         Time time = new Time(Utils.getTimeZone(this, mUpdateTZ));
135         time.set(savedInstanceState.getLong(BUNDLE_KEY_RESTORE_TIME));
136         view.setSelectedDay(time);
137     }
138 
139     @Override
onNewIntent(Intent intent)140     protected void onNewIntent(Intent intent) {
141         long timeMillis = Utils.timeFromIntentInMillis(intent);
142         if (timeMillis > 0) {
143             Time time = new Time(Utils.getTimeZone(this, mUpdateTZ));
144             time.set(timeMillis);
145             goTo(time, false);
146         }
147     }
148 
149     @Override
onResume()150     protected void onResume() {
151         super.onResume();
152         mEventLoader.startBackgroundThread();
153         eventsChanged();
154         CalendarView view = (CalendarView) mViewSwitcher.getNextView();
155         view.updateIs24HourFormat();
156         view.updateView();
157 
158         view = (CalendarView) mViewSwitcher.getCurrentView();
159         view.updateIs24HourFormat();
160         view.updateView();
161 
162         // Register for Intent broadcasts
163         IntentFilter filter = new IntentFilter();
164 
165         filter.addAction(Intent.ACTION_TIME_CHANGED);
166         filter.addAction(Intent.ACTION_DATE_CHANGED);
167         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
168         registerReceiver(mIntentReceiver, filter);
169 
170         mContentResolver.registerContentObserver(Calendar.Events.CONTENT_URI,
171                 true, mObserver);
172     }
173 
174     @Override
onSaveInstanceState(Bundle outState)175     protected void onSaveInstanceState(Bundle outState) {
176         super.onSaveInstanceState(outState);
177 
178         outState.putLong(BUNDLE_KEY_RESTORE_TIME, getSelectedTimeInMillis());
179     }
180 
181     @Override
onPause()182     protected void onPause() {
183         super.onPause();
184         mContentResolver.unregisterContentObserver(mObserver);
185         unregisterReceiver(mIntentReceiver);
186 
187         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
188         view.cleanup();
189         view = (CalendarView) mViewSwitcher.getNextView();
190         view.cleanup();
191         mEventLoader.stopBackgroundThread();
192     }
193 
startProgressSpinner()194     void startProgressSpinner() {
195         // start the progress spinner
196         mProgressBar.setVisibility(View.VISIBLE);
197     }
198 
stopProgressSpinner()199     void stopProgressSpinner() {
200         // stop the progress spinner
201         mProgressBar.setVisibility(View.GONE);
202     }
203 
204     /* Navigator interface methods */
goTo(Time time, boolean animate)205     public void goTo(Time time, boolean animate) {
206         if (animate) {
207             CalendarView current = (CalendarView) mViewSwitcher.getCurrentView();
208             if (current.getSelectedTime().before(time)) {
209                 mViewSwitcher.setInAnimation(mInAnimationForward);
210                 mViewSwitcher.setOutAnimation(mOutAnimationForward);
211             } else {
212                 mViewSwitcher.setInAnimation(mInAnimationBackward);
213                 mViewSwitcher.setOutAnimation(mOutAnimationBackward);
214             }
215         }
216 
217         CalendarView next = (CalendarView) mViewSwitcher.getNextView();
218         next.setSelectedDay(time);
219         next.reloadEvents();
220         mViewSwitcher.showNext();
221         next.requestFocus();
222     }
223 
224     /**
225      * Returns the selected time in milliseconds. The milliseconds are measured
226      * in UTC milliseconds from the epoch and uniquely specifies any selectable
227      * time.
228      *
229      * @return the selected time in milliseconds
230      */
getSelectedTimeInMillis()231     public long getSelectedTimeInMillis() {
232         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
233         return view.getSelectedTimeInMillis();
234     }
235 
getSelectedTime()236     public long getSelectedTime() {
237         return getSelectedTimeInMillis();
238     }
239 
goToToday()240     public void goToToday() {
241         mSelectedDay.set(System.currentTimeMillis());
242         mSelectedDay.normalize(true);
243         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
244         view.setSelectedDay(mSelectedDay);
245         view.reloadEvents();
246     }
247 
getAllDay()248     public boolean getAllDay() {
249         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
250         return view.mSelectionAllDay;
251     }
252 
eventsChanged()253     void eventsChanged() {
254         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
255         view.clearCachedEvents();
256         view.reloadEvents();
257     }
258 
getSelectedEvent()259     Event getSelectedEvent() {
260         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
261         return view.getSelectedEvent();
262     }
263 
isEventSelected()264     boolean isEventSelected() {
265         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
266         return view.isEventSelected();
267     }
268 
getNewEvent()269     Event getNewEvent() {
270         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
271         return view.getNewEvent();
272     }
273 
getNextView()274     public CalendarView getNextView() {
275         return (CalendarView) mViewSwitcher.getNextView();
276     }
277 
switchViews(boolean forward, float xOffSet, float width)278     public View switchViews(boolean forward, float xOffSet, float width) {
279         float progress = Math.abs(xOffSet) / width;
280         if (progress > 1.0f) {
281             progress = 1.0f;
282         }
283 
284         float inFromXValue, inToXValue;
285         float outFromXValue, outToXValue;
286         if (forward) {
287             inFromXValue = 1.0f - progress;
288             inToXValue = 0.0f;
289             outFromXValue = -progress;
290             outToXValue = -1.0f;
291         } else {
292             inFromXValue = progress - 1.0f;
293             inToXValue = 0.0f;
294             outFromXValue = progress;
295             outToXValue = 1.0f;
296         }
297 
298         // We have to allocate these animation objects each time we switch views
299         // because that is the only way to set the animation parameters.
300         TranslateAnimation inAnimation = new TranslateAnimation(
301                 Animation.RELATIVE_TO_SELF, inFromXValue,
302                 Animation.RELATIVE_TO_SELF, inToXValue,
303                 Animation.ABSOLUTE, 0.0f,
304                 Animation.ABSOLUTE, 0.0f);
305 
306         TranslateAnimation outAnimation = new TranslateAnimation(
307                 Animation.RELATIVE_TO_SELF, outFromXValue,
308                 Animation.RELATIVE_TO_SELF, outToXValue,
309                 Animation.ABSOLUTE, 0.0f,
310                 Animation.ABSOLUTE, 0.0f);
311 
312         // Reduce the animation duration based on how far we have already swiped.
313         long duration = (long) (ANIMATION_DURATION * (1.0f - progress));
314         inAnimation.setDuration(duration);
315         outAnimation.setDuration(duration);
316         mViewSwitcher.setInAnimation(inAnimation);
317         mViewSwitcher.setOutAnimation(outAnimation);
318 
319         CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
320         view.cleanup();
321         mViewSwitcher.showNext();
322         view = (CalendarView) mViewSwitcher.getCurrentView();
323         view.requestFocus();
324         view.reloadEvents();
325         return view;
326     }
327 
328     @Override
onPrepareOptionsMenu(Menu menu)329     public boolean onPrepareOptionsMenu(Menu menu) {
330         MenuHelper.onPrepareOptionsMenu(this, menu);
331         return super.onPrepareOptionsMenu(menu);
332     }
333 
334     @Override
onCreateOptionsMenu(Menu menu)335     public boolean onCreateOptionsMenu(Menu menu) {
336         if (! MenuHelper.onCreateOptionsMenu(menu)) {
337             return false;
338         }
339         return super.onCreateOptionsMenu(menu);
340     }
341 
342     @Override
onOptionsItemSelected(MenuItem item)343     public boolean onOptionsItemSelected(MenuItem item) {
344         if (MenuHelper.onOptionsItemSelected(this, item, this)) {
345             return true;
346         }
347         return super.onOptionsItemSelected(item);
348     }
349 
350     @Override
onTouchEvent(MotionEvent ev)351     public boolean onTouchEvent(MotionEvent ev) {
352         if (mGestureDetector.onTouchEvent(ev)) {
353             return true;
354         }
355         return super.onTouchEvent(ev);
356     }
357 
358     class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
359         @Override
onSingleTapUp(MotionEvent ev)360         public boolean onSingleTapUp(MotionEvent ev) {
361             CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
362             view.doSingleTapUp(ev);
363             return true;
364         }
365 
366         @Override
onLongPress(MotionEvent ev)367         public void onLongPress(MotionEvent ev) {
368             CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
369             view.doLongPress(ev);
370         }
371 
372         @Override
onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)373         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
374             CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
375             view.doScroll(e1, e2, distanceX, distanceY);
376             return true;
377         }
378 
379         @Override
onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)380         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
381             CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
382             view.doFling(e1, e2, velocityX, velocityY);
383             return true;
384         }
385 
386         @Override
onDown(MotionEvent ev)387         public boolean onDown(MotionEvent ev) {
388             CalendarView view = (CalendarView) mViewSwitcher.getCurrentView();
389             view.doDown(ev);
390             return true;
391         }
392     }
393 }
394 
395