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.preference.PreferenceManager; 33 import android.provider.Calendar.Events; 34 import android.text.format.DateUtils; 35 import android.text.format.Time; 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 startProgressSpinner()66 protected void startProgressSpinner() { 67 // start the progress spinner 68 mProgressBar.setVisibility(View.VISIBLE); 69 } 70 stopProgressSpinner()71 protected void stopProgressSpinner() { 72 // stop the progress spinner 73 mProgressBar.setVisibility(View.GONE); 74 } 75 76 /* ViewSwitcher.ViewFactory interface methods */ makeView()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 */ goTo(Time time)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 goToToday()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 getSelectedTime()132 public long getSelectedTime() { 133 MonthView mv = (MonthView) mSwitcher.getCurrentView(); 134 return mv.getSelectedTimeInMillis(); 135 } 136 getAllDay()137 public boolean getAllDay() { 138 return false; 139 } 140 getStartDay()141 int getStartDay() { 142 return mStartDay; 143 } 144 eventsChanged()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 onAnimationStart(Animation animation)180 public void onAnimationStart(Animation animation) { 181 } 182 183 // Notifies the MonthView when an animation has finished. onAnimationEnd(Animation animation)184 public void onAnimationEnd(Animation animation) { 185 MonthView monthView = (MonthView) mSwitcher.getCurrentView(); 186 monthView.animationFinished(); 187 } 188 onAnimationRepeat(Animation animation)189 public void onAnimationRepeat(Animation animation) { 190 } 191 192 @Override onCreate(Bundle icicle)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 onPause()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 onResume()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 onSaveInstanceState(Bundle outState)309 protected void onSaveInstanceState(Bundle outState) { 310 super.onSaveInstanceState(outState); 311 outState.putLong(EVENT_BEGIN_TIME, mTime.toMillis(true)); 312 } 313 314 @Override onKeyDown(int keyCode, KeyEvent event)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 onPrepareOptionsMenu(Menu menu)325 public boolean onPrepareOptionsMenu(Menu menu) { 326 MenuHelper.onPrepareOptionsMenu(this, menu); 327 return super.onPrepareOptionsMenu(menu); 328 } 329 330 @Override onCreateOptionsMenu(Menu menu)331 public boolean onCreateOptionsMenu(Menu menu) { 332 MenuHelper.onCreateOptionsMenu(menu); 333 return super.onCreateOptionsMenu(menu); 334 } 335 336 @Override onOptionsItemSelected(MenuItem item)337 public boolean onOptionsItemSelected(MenuItem item) { 338 MenuHelper.onOptionsItemSelected(this, item, this); 339 return super.onOptionsItemSelected(item); 340 } 341 } 342