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