• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.provider.Calendar.Events;
33 import android.text.TextUtils;
34 import android.text.format.DateFormat;
35 import android.text.format.DateUtils;
36 import android.text.format.Time;
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.Animation.AnimationListener;
42 import android.view.animation.AnimationUtils;
43 import android.widget.Gallery.LayoutParams;
44 import android.widget.ProgressBar;
45 import android.widget.TextView;
46 import android.widget.ViewSwitcher;
47 
48 import java.util.Calendar;
49 import java.util.Locale;
50 import java.util.TimeZone;
51 
52 public class MonthActivity extends Activity implements ViewSwitcher.ViewFactory,
53         Navigator, AnimationListener {
54     private static final int INITIAL_HEAP_SIZE = 4 * 1024 * 1024;
55     private Animation mInAnimationPast;
56     private Animation mInAnimationFuture;
57     private Animation mOutAnimationPast;
58     private Animation mOutAnimationFuture;
59     private ViewSwitcher mSwitcher;
60     private Time mTime;
61 
62     private ContentResolver mContentResolver;
63     EventLoader mEventLoader;
64     private int mStartDay;
65 
66     private ProgressBar mProgressBar;
67 
68     // This gets run if the time zone is updated in the db
69     private Runnable mUpdateTZ = new Runnable() {
70         @Override
71         public void run() {
72             // We want mTime to stay on the same day, so we swap the tz
73             mTime.timezone = Utils.getTimeZone(MonthActivity.this, this);
74             mTime.normalize(true);
75             updateTitle(mTime);
76         }
77     };
78 
79     private static final int DAY_OF_WEEK_LABEL_IDS[] = {
80         R.id.day0, R.id.day1, R.id.day2, R.id.day3, R.id.day4, R.id.day5, R.id.day6
81     };
82     private static final int DAY_OF_WEEK_KINDS[] = {
83         Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY,
84         Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY
85     };
86 
startProgressSpinner()87     protected void startProgressSpinner() {
88         // start the progress spinner
89         mProgressBar.setVisibility(View.VISIBLE);
90     }
91 
stopProgressSpinner()92     protected void stopProgressSpinner() {
93         // stop the progress spinner
94         mProgressBar.setVisibility(View.GONE);
95     }
96 
97     /* ViewSwitcher.ViewFactory interface methods */
makeView()98     public View makeView() {
99         MonthView mv = new MonthView(this, this);
100         mv.setLayoutParams(new ViewSwitcher.LayoutParams(
101                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
102         mv.setSelectedTime(mTime);
103         return mv;
104     }
105 
updateTitle(Time time)106     public void updateTitle(Time time) {
107         TextView title = (TextView) findViewById(R.id.title);
108         StringBuffer date = new StringBuffer(Utils.formatMonthYear(this, time));
109         if (!TextUtils.equals(Utils.getTimeZone(this, mUpdateTZ), Time.getCurrentTimezone())) {
110             int flags = DateUtils.FORMAT_SHOW_TIME;
111             if (DateFormat.is24HourFormat(this)) {
112                 flags |= DateUtils.FORMAT_24HOUR;
113             }
114             long start = System.currentTimeMillis();
115             String tz = Utils.getTimeZone(this, mUpdateTZ);
116             boolean isDST = time.isDst != 0;
117             TimeZone timeZone = TimeZone.getTimeZone(tz);
118             date.append(" (").append(Utils.formatDateRange(this, start, start, flags)).append(" ")
119                     .append(timeZone.getDisplayName(isDST, TimeZone.SHORT, Locale.getDefault()))
120                     .append(")");
121         }
122         title.setText(date.toString());
123     }
124 
125     /* Navigator interface methods */
goTo(Time time, boolean animate)126     public void goTo(Time time, boolean animate) {
127         updateTitle(time);
128 
129         MonthView current = (MonthView) mSwitcher.getCurrentView();
130         current.dismissPopup();
131 
132         Time currentTime = current.getTime();
133 
134         // Compute a month number that is monotonically increasing for any
135         // two adjacent months.
136         // This is faster than calling getSelectedTime() because we avoid
137         // a call to Time#normalize().
138         if (animate) {
139             int currentMonth = currentTime.month + currentTime.year * 12;
140             int nextMonth = time.month + time.year * 12;
141             if (nextMonth < currentMonth) {
142                 mSwitcher.setInAnimation(mInAnimationPast);
143                 mSwitcher.setOutAnimation(mOutAnimationPast);
144             } else {
145                 mSwitcher.setInAnimation(mInAnimationFuture);
146                 mSwitcher.setOutAnimation(mOutAnimationFuture);
147             }
148         }
149 
150         MonthView next = (MonthView) mSwitcher.getNextView();
151         next.setSelectionMode(current.getSelectionMode());
152         next.setSelectedTime(time);
153         next.reloadEvents();
154         next.animationStarted();
155         mSwitcher.showNext();
156         next.requestFocus();
157         mTime = time;
158     }
159 
goToToday()160     public void goToToday() {
161         Time now = new Time(Utils.getTimeZone(this, mUpdateTZ));
162         now.set(System.currentTimeMillis());
163         now.minute = 0;
164         now.second = 0;
165         now.normalize(false);
166 
167         TextView title = (TextView) findViewById(R.id.title);
168         title.setText(Utils.formatMonthYear(this, now));
169         mTime = now;
170 
171         MonthView view = (MonthView) mSwitcher.getCurrentView();
172         view.setSelectedTime(now);
173         view.reloadEvents();
174     }
175 
getSelectedTime()176     public long getSelectedTime() {
177         MonthView mv = (MonthView) mSwitcher.getCurrentView();
178         return mv.getSelectedTimeInMillis();
179     }
180 
getAllDay()181     public boolean getAllDay() {
182         return false;
183     }
184 
getStartDay()185     int getStartDay() {
186         return mStartDay;
187     }
188 
eventsChanged()189     void eventsChanged() {
190         MonthView view = (MonthView) mSwitcher.getCurrentView();
191         view.reloadEvents();
192     }
193 
194     /**
195      * Listens for intent broadcasts
196      */
197     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
198         @Override
199         public void onReceive(Context context, Intent intent) {
200             String action = intent.getAction();
201             if (action.equals(Intent.ACTION_TIME_CHANGED)
202                     || action.equals(Intent.ACTION_DATE_CHANGED)
203                     || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
204                 eventsChanged();
205             }
206         }
207     };
208 
209     // Create an observer so that we can update the views whenever a
210     // Calendar event changes.
211     private ContentObserver mObserver = new ContentObserver(new Handler())
212     {
213         @Override
214         public boolean deliverSelfNotifications() {
215             return true;
216         }
217 
218         @Override
219         public void onChange(boolean selfChange) {
220             eventsChanged();
221         }
222     };
223 
onAnimationStart(Animation animation)224     public void onAnimationStart(Animation animation) {
225     }
226 
227     // Notifies the MonthView when an animation has finished.
onAnimationEnd(Animation animation)228     public void onAnimationEnd(Animation animation) {
229         MonthView monthView = (MonthView) mSwitcher.getCurrentView();
230         monthView.animationFinished();
231     }
232 
onAnimationRepeat(Animation animation)233     public void onAnimationRepeat(Animation animation) {
234     }
235 
236     @Override
onCreate(Bundle icicle)237     protected void onCreate(Bundle icicle) {
238         super.onCreate(icicle);
239 
240         // Eliminate extra GCs during startup by setting the initial heap size to 4MB.
241         // TODO: We should restore the old heap size once the activity reaches the idle state
242         VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
243 
244         setContentView(R.layout.month_activity);
245         mContentResolver = getContentResolver();
246 
247         long time;
248         if (icicle != null) {
249             time = icicle.getLong(EVENT_BEGIN_TIME);
250         } else {
251             time = Utils.timeFromIntentInMillis(getIntent());
252         }
253 
254         mTime = new Time(Utils.getTimeZone(this, mUpdateTZ));
255         mTime.set(time);
256         mTime.normalize(true);
257 
258         // Get first day of week based on locale and populate the day headers
259         mStartDay = Calendar.getInstance().getFirstDayOfWeek();
260         int diff = mStartDay - Calendar.SUNDAY - 1;
261         final int startDay = Utils.getFirstDayOfWeek();
262         final int sundayColor = getResources().getColor(R.color.sunday_text_color);
263         final int saturdayColor = getResources().getColor(R.color.saturday_text_color);
264 
265         for (int day = 0; day < 7; day++) {
266             final String dayString = DateUtils.getDayOfWeekString(
267                     (DAY_OF_WEEK_KINDS[day] + diff) % 7 + 1, DateUtils.LENGTH_MEDIUM);
268             final TextView label = (TextView) findViewById(DAY_OF_WEEK_LABEL_IDS[day]);
269             label.setText(dayString);
270             if (Utils.isSunday(day, startDay)) {
271                 label.setTextColor(sundayColor);
272             } else if (Utils.isSaturday(day, startDay)) {
273                 label.setTextColor(saturdayColor);
274             }
275         }
276 
277         // Set the initial title
278         TextView title = (TextView) findViewById(R.id.title);
279         title.setText(Utils.formatMonthYear(this, mTime));
280 
281         mEventLoader = new EventLoader(this);
282         mProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
283 
284         mSwitcher = (ViewSwitcher) findViewById(R.id.switcher);
285         mSwitcher.setFactory(this);
286         mSwitcher.getCurrentView().requestFocus();
287 
288         mInAnimationPast = AnimationUtils.loadAnimation(this, R.anim.slide_down_in);
289         mOutAnimationPast = AnimationUtils.loadAnimation(this, R.anim.slide_down_out);
290         mInAnimationFuture = AnimationUtils.loadAnimation(this, R.anim.slide_up_in);
291         mOutAnimationFuture = AnimationUtils.loadAnimation(this, R.anim.slide_up_out);
292 
293         mInAnimationPast.setAnimationListener(this);
294         mInAnimationFuture.setAnimationListener(this);
295     }
296 
297     @Override
onNewIntent(Intent intent)298     protected void onNewIntent(Intent intent) {
299         long timeMillis = Utils.timeFromIntentInMillis(intent);
300         if (timeMillis > 0) {
301             Time time = new Time(Utils.getTimeZone(this, mUpdateTZ));
302             time.set(timeMillis);
303             goTo(time, false);
304         }
305     }
306 
307     @Override
onPause()308     protected void onPause() {
309         super.onPause();
310         if (isFinishing()) {
311             mEventLoader.stopBackgroundThread();
312         }
313         mContentResolver.unregisterContentObserver(mObserver);
314         unregisterReceiver(mIntentReceiver);
315 
316         MonthView view = (MonthView) mSwitcher.getCurrentView();
317         view.dismissPopup();
318         view = (MonthView) mSwitcher.getNextView();
319         view.dismissPopup();
320         mEventLoader.stopBackgroundThread();
321     }
322 
323     @Override
onResume()324     protected void onResume() {
325         super.onResume();
326         mUpdateTZ.run();
327         mEventLoader.startBackgroundThread();
328         eventsChanged();
329 
330         MonthView view1 = (MonthView) mSwitcher.getCurrentView();
331         MonthView view2 = (MonthView) mSwitcher.getNextView();
332         SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(this);
333         String str = prefs.getString(CalendarPreferenceActivity.KEY_DETAILED_VIEW,
334                 CalendarPreferenceActivity.DEFAULT_DETAILED_VIEW);
335         view1.updateView();
336         view2.updateView();
337         view1.setDetailedView(str);
338         view2.setDetailedView(str);
339 
340         // Register for Intent broadcasts
341         IntentFilter filter = new IntentFilter();
342 
343         filter.addAction(Intent.ACTION_TIME_CHANGED);
344         filter.addAction(Intent.ACTION_DATE_CHANGED);
345         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
346         registerReceiver(mIntentReceiver, filter);
347 
348         mContentResolver.registerContentObserver(Events.CONTENT_URI,
349                 true, mObserver);
350 
351         // Record Month View as the (new) start view
352         Utils.setDefaultView(this, CalendarApplication.MONTH_VIEW_ID);
353     }
354 
355     @Override
onSaveInstanceState(Bundle outState)356     protected void onSaveInstanceState(Bundle outState) {
357         super.onSaveInstanceState(outState);
358         outState.putLong(EVENT_BEGIN_TIME, mTime.toMillis(true));
359     }
360 
361     @Override
onPrepareOptionsMenu(Menu menu)362     public boolean onPrepareOptionsMenu(Menu menu) {
363         MenuHelper.onPrepareOptionsMenu(this, menu);
364         return super.onPrepareOptionsMenu(menu);
365     }
366 
367     @Override
onCreateOptionsMenu(Menu menu)368     public boolean onCreateOptionsMenu(Menu menu) {
369         MenuHelper.onCreateOptionsMenu(menu);
370         return super.onCreateOptionsMenu(menu);
371     }
372 
373     @Override
onOptionsItemSelected(MenuItem item)374     public boolean onOptionsItemSelected(MenuItem item) {
375         MenuHelper.onOptionsItemSelected(this, item, this);
376         return super.onOptionsItemSelected(item);
377     }
378 }
379