Initial Contribution
[android/platform/packages/apps/Calendar.git] / src / com / android / calendar / MonthActivity.java
1 /*
2  * Copyright (C) 2006 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 static android.provider.Calendar.EVENT_BEGIN_TIME;
20 import dalvik.system.VMRuntime;
21
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.content.SharedPreferences;
29 import android.database.ContentObserver;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.pim.DateUtils;
33 import android.pim.Time;
34 import android.preference.PreferenceManager;
35 import android.provider.Calendar.Events;
36 import android.view.KeyEvent;
37 import android.view.Menu;
38 import android.view.MenuItem;
39 import android.view.View;
40 import android.view.animation.Animation;
41 import android.view.animation.AnimationUtils;
42 import android.view.animation.Animation.AnimationListener;
43 import android.widget.ProgressBar;
44 import android.widget.TextView;
45 import android.widget.ViewSwitcher;
46 import android.widget.Gallery.LayoutParams;
47
48 import java.util.Calendar;
49
50 public class MonthActivity extends Activity implements ViewSwitcher.ViewFactory,
51         Navigator, AnimationListener {
52     private static final int INITIAL_HEAP_SIZE = 4 * 1024 * 1024;
53     private Animation mInAnimationPast;
54     private Animation mInAnimationFuture;
55     private Animation mOutAnimationPast;
56     private Animation mOutAnimationFuture;
57     private ViewSwitcher mSwitcher;
58     private Time mTime;
59
60     private ContentResolver mContentResolver;
61     EventLoader mEventLoader;
62     private int mStartDay;
63
64     private ProgressBar mProgressBar;
65
66     protected void startProgressSpinner() {
67         // start the progress spinner
68         mProgressBar.setVisibility(View.VISIBLE);
69     }
70
71     protected void stopProgressSpinner() {
72         // stop the progress spinner
73         mProgressBar.setVisibility(View.GONE);
74     }
75
76     /* ViewSwitcher.ViewFactory interface methods */
77     public View makeView() {
78         MonthView mv = new MonthView(this, this);
79         mv.setLayoutParams(new ViewSwitcher.LayoutParams(
80                 LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
81         mv.setSelectedTime(mTime);
82         return mv;
83     }
84
85     /* Navigator interface methods */
86     public void goTo(Time time) {
87         TextView title = (TextView) findViewById(R.id.title);
88         title.setText(Utils.formatMonthYear(time));
89
90         MonthView current = (MonthView) mSwitcher.getCurrentView();
91         current.dismissPopup();
92
93         Time currentTime = current.getTime();
94
95         // Compute a month number that is monotonically increasing for any
96         // two adjacent months.
97         // This is faster than calling getSelectedTime() because we avoid
98         // a call to Time#normalize().
99         int currentMonth = currentTime.month + currentTime.year * 12;
100         int nextMonth = time.month + time.year * 12;
101         if (nextMonth < currentMonth) {
102             mSwitcher.setInAnimation(mInAnimationPast);
103             mSwitcher.setOutAnimation(mOutAnimationPast);
104         } else {
105             mSwitcher.setInAnimation(mInAnimationFuture);
106             mSwitcher.setOutAnimation(mOutAnimationFuture);
107         }
108
109         MonthView next = (MonthView) mSwitcher.getNextView();
110         next.setSelectionMode(current.getSelectionMode());
111         next.setSelectedTime(time);
112         next.reloadEvents();
113         next.animationStarted();
114         mSwitcher.showNext();
115         next.requestFocus();
116         mTime = time;
117     }
118
119     public void goToToday() {
120         Time now = new Time();
121         now.set(System.currentTimeMillis());
122
123         TextView title = (TextView) findViewById(R.id.title);
124         title.setText(Utils.formatMonthYear(now));
125         mTime = now;
126
127         MonthView view = (MonthView) mSwitcher.getCurrentView();
128         view.setSelectedTime(now);
129         view.reloadEvents();
130     }
131
132     public long getSelectedTime() {
133         MonthView mv = (MonthView) mSwitcher.getCurrentView();
134         return mv.getSelectedTimeInMillis();
135     }
136
137     public boolean getAllDay() {
138         return false;
139     }
140
141     int getStartDay() {
142         return mStartDay;
143     }
144
145     void eventsChanged() {
146         MonthView view = (MonthView) mSwitcher.getCurrentView();
147         view.reloadEvents();
148     }
149
150     /**
151      * Listens for intent broadcasts
152      */
153     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
154         @Override
155         public void onReceive(Context context, Intent intent) {
156             String action = intent.getAction();
157             if (action.equals(Intent.ACTION_TIME_CHANGED)
158                     || action.equals(Intent.ACTION_DATE_CHANGED)
159                     || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
160                 eventsChanged();
161             }
162         }
163     };
164
165     // Create an observer so that we can update the views whenever a
166     // Calendar event changes.
167     private ContentObserver mObserver = new ContentObserver(new Handler())
168     {
169         @Override
170         public boolean deliverSelfNotifications() {
171             return true;
172         }
173
174         @Override
175         public void onChange(boolean selfChange) {
176             eventsChanged();
177         }
178     };
179
180     public void onAnimationStart(Animation animation) {
181     }
182
183     // Notifies the MonthView when an animation has finished.
184     public void onAnimationEnd(Animation animation) {
185         MonthView monthView = (MonthView) mSwitcher.getCurrentView();
186         monthView.animationFinished();
187     }
188
189     public void onAnimationRepeat(Animation animation) {
190     }
191
192     @Override
193     protected void onCreate(Bundle icicle) {
194         super.onCreate(icicle);
195
196         // Eliminate extra GCs during startup by setting the initial heap size to 4MB.
197         // TODO: We should restore the old heap size once the activity reaches the idle state
198         long oldHeapSize = VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
199
200         setContentView(R.layout.month_activity);
201         mContentResolver = getContentResolver();
202
203         long time;
204         if (icicle != null) {
205             time = icicle.getLong(EVENT_BEGIN_TIME);
206         } else {
207             time = Utils.timeFromIntentInMillis(getIntent());
208         }
209
210         mTime = new Time();
211         mTime.set(time);
212         mTime.normalize(true);
213
214         // Get first day of week based on locale and populate the day headers
215         mStartDay = Calendar.getInstance().getFirstDayOfWeek();
216         int diff = mStartDay - Calendar.SUNDAY - 1;
217
218         String dayString = DateUtils.getDayOfWeekString((Calendar.SUNDAY + diff) % 7 + 1,
219                 DateUtils.LENGTH_MEDIUM);
220         ((TextView) findViewById(R.id.day0)).setText(dayString);
221         dayString = DateUtils.getDayOfWeekString((Calendar.MONDAY + diff) % 7 + 1,
222                 DateUtils.LENGTH_MEDIUM);
223         ((TextView) findViewById(R.id.day1)).setText(dayString);
224         dayString = DateUtils.getDayOfWeekString((Calendar.TUESDAY + diff) % 7 + 1,
225                 DateUtils.LENGTH_MEDIUM);
226         ((TextView) findViewById(R.id.day2)).setText(dayString);
227         dayString = DateUtils.getDayOfWeekString((Calendar.WEDNESDAY + diff) % 7 + 1,
228                 DateUtils.LENGTH_MEDIUM);
229         ((TextView) findViewById(R.id.day3)).setText(dayString);
230         dayString = DateUtils.getDayOfWeekString((Calendar.THURSDAY + diff) % 7 + 1,
231                 DateUtils.LENGTH_MEDIUM);
232         ((TextView) findViewById(R.id.day4)).setText(dayString);
233         dayString = DateUtils.getDayOfWeekString((Calendar.FRIDAY + diff) % 7 + 1,
234                 DateUtils.LENGTH_MEDIUM);
235         ((TextView) findViewById(R.id.day5)).setText(dayString);
236         dayString = DateUtils.getDayOfWeekString((Calendar.SATURDAY + diff) % 7 + 1,
237                 DateUtils.LENGTH_MEDIUM);
238         ((TextView) findViewById(R.id.day6)).setText(dayString);
239
240         // Set the initial title
241         TextView title = (TextView) findViewById(R.id.title);
242         title.setText(Utils.formatMonthYear(mTime));
243
244         mEventLoader = new EventLoader(this);
245         mProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
246
247         mSwitcher = (ViewSwitcher) findViewById(R.id.switcher);
248         mSwitcher.setFactory(this);
249         mSwitcher.getCurrentView().requestFocus();
250
251         mInAnimationPast = AnimationUtils.loadAnimation(this, R.anim.slide_down_in);
252         mOutAnimationPast = AnimationUtils.loadAnimation(this, R.anim.slide_down_out);
253         mInAnimationFuture = AnimationUtils.loadAnimation(this, R.anim.slide_up_in);
254         mOutAnimationFuture = AnimationUtils.loadAnimation(this, R.anim.slide_up_out);
255
256         mInAnimationPast.setAnimationListener(this);
257         mInAnimationFuture.setAnimationListener(this);
258     }
259
260     @Override
261     protected void onPause() {
262         super.onPause();
263         if (isFinishing()) {
264             mEventLoader.stopBackgroundThread();
265         }
266         mContentResolver.unregisterContentObserver(mObserver);
267         unregisterReceiver(mIntentReceiver);
268
269         MonthView view = (MonthView) mSwitcher.getCurrentView();
270         view.dismissPopup();
271         view = (MonthView) mSwitcher.getNextView();
272         view.dismissPopup();
273         mEventLoader.stopBackgroundThread();
274     }
275
276     @Override
277     protected void onResume() {
278         super.onResume();
279         mEventLoader.startBackgroundThread();
280         eventsChanged();
281
282         MonthView view1 = (MonthView) mSwitcher.getCurrentView();
283         MonthView view2 = (MonthView) mSwitcher.getNextView();
284         SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
285         String str = prefs.getString(CalendarPreferenceActivity.KEY_DETAILED_VIEW,
286                 CalendarPreferenceActivity.DEFAULT_DETAILED_VIEW);
287         view1.setDetailedView(str);
288         view2.setDetailedView(str);
289
290         // Record Month View as the (new) start view
291         String activityString = CalendarApplication.ACTIVITY_NAMES[CalendarApplication.MONTH_VIEW_ID];
292         SharedPreferences.Editor editor = prefs.edit();
293         editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
294         editor.commit();
295
296         // Register for Intent broadcasts
297         IntentFilter filter = new IntentFilter();
298
299         filter.addAction(Intent.ACTION_TIME_CHANGED);
300         filter.addAction(Intent.ACTION_DATE_CHANGED);
301         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
302         registerReceiver(mIntentReceiver, filter);
303
304         mContentResolver.registerContentObserver(Events.CONTENT_URI,
305                 true, mObserver);
306     }
307
308     @Override
309     protected void onSaveInstanceState(Bundle outState) {
310         super.onSaveInstanceState(outState);
311         outState.putLong(EVENT_BEGIN_TIME, mTime.toMillis(true));
312     }
313
314     @Override
315     public boolean onKeyDown(int keyCode, KeyEvent event) {
316         switch (keyCode) {
317             case KeyEvent.KEYCODE_BACK:
318                 finish();
319                 return true;
320         }
321         return super.onKeyDown(keyCode, event);
322     }
323
324     @Override
325     public boolean onPrepareOptionsMenu(Menu menu) {
326         MenuHelper.onPrepareOptionsMenu(this, menu);
327         return super.onPrepareOptionsMenu(menu);
328     }
329
330     @Override
331     public boolean onCreateOptionsMenu(Menu menu) {
332         MenuHelper.onCreateOptionsMenu(menu);
333         return super.onCreateOptionsMenu(menu);
334     }
335
336     @Override
337     public boolean onOptionsItemSelected(MenuItem item) {
338         MenuHelper.onOptionsItemSelected(this, item, this);
339         return super.onOptionsItemSelected(item);
340     }
341 }