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 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.util.Log; 38 import android.view.KeyEvent; 39 import android.view.Menu; 40 import android.view.MenuItem; 41 42 import java.util.Locale; 43 import java.util.TimeZone; 44 45 public class AgendaActivity extends Activity implements Navigator { 46 47 private static final String TAG = "AgendaActivity"; 48 49 private static boolean DEBUG = false; 50 51 protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time"; 52 53 private static final long INITIAL_HEAP_SIZE = 4*1024*1024; 54 55 private ContentResolver mContentResolver; 56 57 private AgendaListView mAgendaListView; 58 59 private Time mTime; 60 61 private String mTitle; 62 63 // This gets run if the time zone is updated in the db 64 private Runnable mUpdateTZ = new Runnable() { 65 @Override 66 public void run() { 67 long time = mTime.toMillis(true); 68 mTime = new Time(Utils.getTimeZone(AgendaActivity.this, this)); 69 mTime.set(time); 70 updateTitle(); 71 } 72 }; 73 74 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 75 @Override 76 public void onReceive(Context context, Intent intent) { 77 String action = intent.getAction(); 78 if (action.equals(Intent.ACTION_TIME_CHANGED) 79 || action.equals(Intent.ACTION_DATE_CHANGED) 80 || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { 81 mAgendaListView.refresh(true); 82 } 83 } 84 }; 85 86 private ContentObserver mObserver = new ContentObserver(new Handler()) { 87 @Override 88 public boolean deliverSelfNotifications() { 89 return true; 90 } 91 92 @Override 93 public void onChange(boolean selfChange) { 94 mAgendaListView.refresh(true); 95 } 96 }; 97 98 @Override 99 protected void onCreate(Bundle icicle) { 100 super.onCreate(icicle); 101 102 // Eliminate extra GCs during startup by setting the initial heap size to 4MB. 103 // TODO: We should restore the old heap size once the activity reaches the idle state 104 VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE); 105 106 mAgendaListView = new AgendaListView(this); 107 setContentView(mAgendaListView); 108 109 mContentResolver = getContentResolver(); 110 111 mTitle = getResources().getString(R.string.agenda_view); 112 113 long millis = 0; 114 mTime = new Time(Utils.getTimeZone(this, mUpdateTZ)); 115 if (icicle != null) { 116 // Returns 0 if key not found 117 millis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME); 118 if (DEBUG) { 119 Log.v(TAG, "Restore value from icicle: " + millis); 120 } 121 } 122 123 if (millis == 0) { 124 // Returns 0 if key not found 125 millis = getIntent().getLongExtra(EVENT_BEGIN_TIME, 0); 126 if (DEBUG) { 127 Time time = new Time(); 128 time.set(millis); 129 Log.v(TAG, "Restore value from intent: " + time.toString()); 130 } 131 } 132 133 if (millis == 0) { 134 if (DEBUG) { 135 Log.v(TAG, "Restored from current time"); 136 } 137 millis = System.currentTimeMillis(); 138 } 139 mTime.set(millis); 140 updateTitle(); 141 } 142 143 private void updateTitle() { 144 StringBuilder title = new StringBuilder(mTitle); 145 String tz = Utils.getTimeZone(this, mUpdateTZ); 146 if (!TextUtils.equals(tz, Time.getCurrentTimezone())) { 147 int flags = DateUtils.FORMAT_SHOW_TIME; 148 if (DateFormat.is24HourFormat(this)) { 149 flags |= DateUtils.FORMAT_24HOUR; 150 } 151 boolean isDST = mTime.isDst != 0; 152 long start = System.currentTimeMillis(); 153 TimeZone timeZone = TimeZone.getTimeZone(tz); 154 title.append(" (").append(Utils.formatDateRange(this, start, start, flags)).append(" ") 155 .append(timeZone.getDisplayName(isDST, TimeZone.SHORT, Locale.getDefault())) 156 .append(")"); 157 } 158 setTitle(title.toString()); 159 } 160 161 @Override 162 protected void onNewIntent(Intent intent) { 163 long time = Utils.timeFromIntentInMillis(intent); 164 if (time > 0) { 165 mTime.set(time); 166 goTo(mTime, false); 167 } 168 } 169 170 @Override 171 protected void onResume() { 172 super.onResume(); 173 if (DEBUG) { 174 Log.v(TAG, "OnResume to " + mTime.toString()); 175 } 176 177 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences( 178 getApplicationContext()); 179 boolean hideDeclined = prefs.getBoolean( 180 CalendarPreferenceActivity.KEY_HIDE_DECLINED, false); 181 182 mAgendaListView.setHideDeclinedEvents(hideDeclined); 183 mAgendaListView.goTo(mTime, true); 184 mAgendaListView.onResume(); 185 186 // Register for Intent broadcasts 187 IntentFilter filter = new IntentFilter(); 188 filter.addAction(Intent.ACTION_TIME_CHANGED); 189 filter.addAction(Intent.ACTION_DATE_CHANGED); 190 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 191 registerReceiver(mIntentReceiver, filter); 192 193 mContentResolver.registerContentObserver(Events.CONTENT_URI, true, mObserver); 194 mUpdateTZ.run(); 195 196 // Record Agenda View as the (new) default detailed view. 197 Utils.setDefaultView(this, CalendarApplication.AGENDA_VIEW_ID); 198 } 199 200 @Override 201 protected void onSaveInstanceState(Bundle outState) { 202 super.onSaveInstanceState(outState); 203 204 long firstVisibleTime = mAgendaListView.getFirstVisibleTime(); 205 if (firstVisibleTime > 0) { 206 mTime.set(firstVisibleTime); 207 outState.putLong(BUNDLE_KEY_RESTORE_TIME, firstVisibleTime); 208 if (DEBUG) { 209 Log.v(TAG, "onSaveInstanceState " + mTime.toString()); 210 } 211 } 212 } 213 214 @Override 215 protected void onPause() { 216 super.onPause(); 217 218 mAgendaListView.onPause(); 219 mContentResolver.unregisterContentObserver(mObserver); 220 unregisterReceiver(mIntentReceiver); 221 } 222 223 @Override 224 public boolean onPrepareOptionsMenu(Menu menu) { 225 MenuHelper.onPrepareOptionsMenu(this, menu); 226 return super.onPrepareOptionsMenu(menu); 227 } 228 229 @Override 230 public boolean onCreateOptionsMenu(Menu menu) { 231 MenuHelper.onCreateOptionsMenu(menu); 232 return super.onCreateOptionsMenu(menu); 233 } 234 235 @Override 236 public boolean onOptionsItemSelected(MenuItem item) { 237 MenuHelper.onOptionsItemSelected(this, item, this); 238 return super.onOptionsItemSelected(item); 239 } 240 241 @Override 242 public boolean onKeyDown(int keyCode, KeyEvent event) { 243 switch (keyCode) { 244 case KeyEvent.KEYCODE_DEL: 245 // Delete the currently selected event (if any) 246 mAgendaListView.deleteSelectedEvent(); 247 break; 248 } 249 return super.onKeyDown(keyCode, event); 250 } 251 252 /* Navigator interface methods */ 253 public void goToToday() { 254 Time now = new Time(Utils.getTimeZone(this, mUpdateTZ)); 255 now.setToNow(); 256 mAgendaListView.goTo(now, true); // Force refresh 257 } 258 259 public void goTo(Time time, boolean animate) { 260 mAgendaListView.goTo(time, false); 261 } 262 263 public long getSelectedTime() { 264 return mAgendaListView.getSelectedTime(); 265 } 266 267 public boolean getAllDay() { 268 return false; 269 } 270 } 271 272