AgendaFragment.java revision 9a39bddb8e519b710a06d1c77257de6962ae5f72
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 17package com.android.calendar.agenda; 18 19 20import android.app.Activity; 21import android.app.Fragment; 22import android.app.FragmentManager; 23import android.app.FragmentTransaction; 24import android.content.Context; 25import android.content.SharedPreferences; 26import android.os.Bundle; 27import android.text.format.Time; 28import android.util.Log; 29import android.view.LayoutInflater; 30import android.view.View; 31import android.view.ViewGroup; 32import android.widget.AbsListView; 33import android.widget.AbsListView.OnScrollListener; 34import android.widget.Adapter; 35import android.widget.HeaderViewListAdapter; 36import android.widget.ListView; 37 38import com.android.calendar.CalendarController; 39import com.android.calendar.CalendarController.EventInfo; 40import com.android.calendar.CalendarController.EventType; 41import com.android.calendar.CalendarController.ViewType; 42import com.android.calendar.GeneralPreferences; 43import com.android.calendar.R; 44import com.android.calendar.StickyHeaderListView; 45import com.android.calendar.StickyHeaderListView.HeaderIndexer; 46import com.android.calendar.Utils; 47import com.android.calendar.event.EditEventFragment; 48 49 50public class AgendaFragment extends Fragment implements CalendarController.EventHandler, 51 OnScrollListener { 52 53 private static final String TAG = AgendaFragment.class.getSimpleName(); 54 private static boolean DEBUG = false; 55 56 protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time"; 57 protected static final String BUNDLE_KEY_RESTORE_INSTANCE_ID = "key_restore_instance_id"; 58 private static final long INITIAL_HEAP_SIZE = 4*1024*1024; 59 60 private AgendaListView mAgendaListView; 61 private Activity mActivity; 62 private Time mTime; 63 private String mTimeZone; 64 private long mInitialTimeMillis; 65 private boolean mShowEventDetailsWithAgenda; 66 private CalendarController mController; 67 private EditEventFragment mEventFragment; 68 private String mQuery; 69 private boolean mUsedForSearch = false; 70 private boolean mIsTabletConfig; 71 72 // Tracks the time of the top visible view in order to send UPDATE_TITLE messages to the action 73 // bar. 74 int mJulianDayOnTop = -1; 75 76 private Runnable mTZUpdater = new Runnable() { 77 @Override 78 public void run() { 79 mTimeZone = Utils.getTimeZone(getActivity(), this); 80 mTime = new Time(mTimeZone); 81 } 82 }; 83 84 public AgendaFragment() { 85 this(0, false); 86 } 87 88 89 // timeMillis - time of first event to show 90 // usedForSearch - indicates if this fragment is used in the search fragment 91 public AgendaFragment(long timeMillis, boolean usedForSearch) { 92 mInitialTimeMillis = timeMillis; 93 mTime = new Time(); 94 mUsedForSearch = usedForSearch; 95 } 96 97 @Override 98 public void onAttach(Activity activity) { 99 super.onAttach(activity); 100 mTimeZone = Utils.getTimeZone(activity, mTZUpdater); 101 mTime = new Time(mTimeZone); 102 if (mInitialTimeMillis == 0) { 103 mTime.setToNow(); 104 } else { 105 mTime.set(mInitialTimeMillis); 106 } 107 mActivity = activity; 108 } 109 110 @Override 111 public void onCreate(Bundle icicle) { 112 super.onCreate(icicle); 113 mController = CalendarController.getInstance(mActivity); 114 mShowEventDetailsWithAgenda = 115 Utils.getConfigBool(mActivity, R.bool.show_event_details_with_agenda); 116 mIsTabletConfig = 117 Utils.getConfigBool(mActivity, R.bool.tablet_config); 118 } 119 120 @Override 121 public View onCreateView(LayoutInflater inflater, ViewGroup container, 122 Bundle savedInstanceState) { 123 124 long instanceId = -1; 125 if (savedInstanceState != null) { 126 instanceId = savedInstanceState.getLong(BUNDLE_KEY_RESTORE_INSTANCE_ID); 127 } 128 129 View v = inflater.inflate(R.layout.agenda_fragment, null); 130 131 mAgendaListView = (AgendaListView)v.findViewById(R.id.agenda_events_list); 132 mAgendaListView.goTo(mTime, -1, mQuery, false); 133 if (!mShowEventDetailsWithAgenda) { 134 v.findViewById(R.id.agenda_event_info).setVisibility(View.GONE); 135 } 136 137 // Set adapter & HeaderIndexer for StickyHeaderListView 138 StickyHeaderListView lv = 139 (StickyHeaderListView)v.findViewById(R.id.agenda_sticky_header_list); 140 if (lv != null) { 141 Adapter a = mAgendaListView.getAdapter(); 142 lv.setAdapter(a); 143 if (a instanceof HeaderViewListAdapter) { 144 lv.setIndexer((HeaderIndexer) ((HeaderViewListAdapter)a).getWrappedAdapter()); 145 } else if (a instanceof AgendaWindowAdapter) { 146 lv.setIndexer((HeaderIndexer) a); 147 } else { 148 Log.wtf(TAG, "Cannot find HeaderIndexer for StickyHeaderListView"); 149 } 150 151 // Set scroll listener so that the date on the ActionBar can be set while 152 // the user scrolls the view 153 if (!mIsTabletConfig) { 154 lv.setOnScrollListener(this); 155 } 156 } 157 return v; 158 } 159 160 @Override 161 public void onResume() { 162 super.onResume(); 163 if (DEBUG) { 164 Log.v(TAG, "OnResume to " + mTime.toString()); 165 } 166 167 SharedPreferences prefs = GeneralPreferences.getSharedPreferences( 168 getActivity()); 169 boolean hideDeclined = prefs.getBoolean( 170 GeneralPreferences.KEY_HIDE_DECLINED, false); 171 172 mAgendaListView.setHideDeclinedEvents(hideDeclined); 173 mAgendaListView.goTo(mTime, -1, mQuery, true); 174 mAgendaListView.onResume(); 175 176// // Register for Intent broadcasts 177// IntentFilter filter = new IntentFilter(); 178// filter.addAction(Intent.ACTION_TIME_CHANGED); 179// filter.addAction(Intent.ACTION_DATE_CHANGED); 180// filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 181// registerReceiver(mIntentReceiver, filter); 182// 183// mContentResolver.registerContentObserver(Events.CONTENT_URI, true, mObserver); 184 } 185 186 @Override 187 public void onSaveInstanceState(Bundle outState) { 188 super.onSaveInstanceState(outState); 189 190 long firstVisibleTime = mAgendaListView.getFirstVisibleTime(); 191 if (firstVisibleTime > 0) { 192 mTime.set(firstVisibleTime); 193 outState.putLong(BUNDLE_KEY_RESTORE_TIME, firstVisibleTime); 194 if (DEBUG) { 195 Log.v(TAG, "onSaveInstanceState " + mTime.toString()); 196 } 197 } 198 199 long selectedInstance = mAgendaListView.getSelectedInstanceId(); 200 if (selectedInstance >= 0) { 201 outState.putLong(BUNDLE_KEY_RESTORE_INSTANCE_ID, selectedInstance); 202 } 203 } 204 205 /** 206 * This cleans up the event info fragment since the FragmentManager doesn't 207 * handle nested fragments. Without this, the action bar buttons added by 208 * the info fragment can come back on a rotation. 209 * 210 * @param fragmentManager 211 */ 212 public void removeFragments(FragmentManager fragmentManager) { 213 mController.deregisterEventHandler(R.id.agenda_event_info); 214 if (getActivity().isFinishing()) { 215 return; 216 } 217 FragmentTransaction ft = fragmentManager.beginTransaction(); 218 Fragment f = fragmentManager.findFragmentById(R.id.agenda_event_info); 219 if (f != null) { 220 ft.remove(f); 221 } 222 ft.commit(); 223 } 224 225 @Override 226 public void onPause() { 227 super.onPause(); 228 229 mAgendaListView.onPause(); 230// mContentResolver.unregisterContentObserver(mObserver); 231// unregisterReceiver(mIntentReceiver); 232 233 // Record Agenda View as the (new) default detailed view. 234// Utils.setDefaultView(this, CalendarApplication.AGENDA_VIEW_ID); 235 } 236 237 private void goTo(EventInfo event, boolean animate) { 238 if (mAgendaListView == null) { 239 // The view hasn't been set yet. Just save the time and use it 240 // later. 241 mTime.set(event.startTime); 242 return; 243 } 244 mAgendaListView.goTo(event.startTime, event.id, mQuery, false); 245 showEventInfo(event); 246 } 247 248 private void search(String query, Time time) { 249 mQuery = query; 250 if (time != null) { 251 mTime.set(time); 252 } 253 if (mAgendaListView == null) { 254 // The view hasn't been set yet. Just return. 255 return; 256 } 257 mAgendaListView.goTo(time, -1, mQuery, true); 258 } 259 260 @Override 261 public void eventsChanged() { 262 mAgendaListView.refresh(true); 263 } 264 265 @Override 266 public long getSupportedEventTypes() { 267 return EventType.GO_TO | EventType.EVENTS_CHANGED | ((mUsedForSearch)?EventType.SEARCH:0); 268 } 269 270 @Override 271 public void handleEvent(EventInfo event) { 272 if (event.eventType == EventType.GO_TO) { 273 // TODO support a range of time 274 // TODO support event_id 275 // TODO figure out the animate bit 276 goTo(event, true); 277 } else if (event.eventType == EventType.SEARCH) { 278 search(event.query, event.startTime); 279 } else if (event.eventType == EventType.EVENTS_CHANGED) { 280 eventsChanged(); 281 } 282 } 283 284 285 // Shows the selected event in the Agenda view 286 private void showEventInfo(EventInfo event) { 287 288 // Ignore unknown events 289 if (event.id == -1) { 290 Log.e(TAG, "showEventInfo, event ID = " + event.id); 291 return; 292 } 293 294 // Create a fragment to show the event to the side of the agenda list 295 if (mShowEventDetailsWithAgenda) { 296 FragmentManager fragmentManager = getFragmentManager(); 297 FragmentTransaction ft = fragmentManager.beginTransaction(); 298 mEventFragment = new EditEventFragment(event, true, null); 299 ft.replace(R.id.agenda_event_info, mEventFragment); 300 mController.registerEventHandler(R.id.agenda_event_info, 301 mEventFragment); 302 ft.commit(); 303 } 304 /* 305 * else { Intent intent = new Intent(Intent.ACTION_VIEW); Uri eventUri 306 * = ContentUris.withAppendedId(Events.CONTENT_URI, event.id); 307 * intent.setData(eventUri); // intent.setClassName(this, 308 * EventInfoActivity.class.getName()); 309 * intent.putExtra(EVENT_BEGIN_TIME, event.startTime != null ? 310 * event.startTime.toMillis(true) : -1); intent.putExtra( 311 * EVENT_END_TIME, event.endTime != null ? event.endTime.toMillis(true) 312 * : -1); startActivity(intent); } 313 */ 314 } 315 316 // OnScrollListener implementation to update the date on the pull-down menu of the app 317 318 public void onScrollStateChanged(AbsListView view, int scrollState) { 319 // Do nothing 320 } 321 322 // Gets the time of the first visible view. If it is a new time, send a message to update 323 // the time on the ActionBar 324 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 325 int totalItemCount) { 326 int julianDay = mAgendaListView.getJulianDayFromPosition(firstVisibleItem - 327 mAgendaListView.getHeaderViewsCount()); 328 // On error - leave the old view 329 if (julianDay == 0) { 330 return; 331 } 332 // If the day changed, update the ActionBar 333 if (mJulianDayOnTop != julianDay) { 334 mJulianDayOnTop = julianDay; 335 Time t = new Time(mTimeZone); 336 t.setJulianDay(mJulianDayOnTop); 337 mController.sendEvent(this, EventType.UPDATE_TITLE, t, t, null, -1, 338 ViewType.CURRENT, 0, null, null); 339 } 340 } 341} 342