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