SearchActivity.java revision 6b858fc6f8afad95a075595016c5c22547924886
1/* 2 * Copyright (C) 2010 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 */ 16package com.android.calendar; 17 18import static android.provider.Calendar.EVENT_BEGIN_TIME; 19import static android.provider.Calendar.EVENT_END_TIME; 20 21import com.android.calendar.CalendarController.EventInfo; 22import com.android.calendar.CalendarController.EventType; 23import com.android.calendar.CalendarController.ViewType; 24import com.android.calendar.agenda.AgendaFragment; 25 26import dalvik.system.VMRuntime; 27 28import android.app.Activity; 29import android.app.FragmentManager; 30import android.app.FragmentTransaction; 31import android.app.SearchManager; 32import android.content.ContentResolver; 33import android.content.ContentUris; 34import android.content.Intent; 35import android.content.res.Configuration; 36import android.database.ContentObserver; 37import android.net.Uri; 38import android.os.Bundle; 39import android.os.Handler; 40import android.provider.Calendar.Events; 41import android.provider.SearchRecentSuggestions; 42import android.text.format.Time; 43import android.util.Log; 44import android.view.Menu; 45import android.view.MenuItem; 46import android.view.View; 47import android.widget.SearchView; 48 49public class SearchActivity extends Activity 50 implements CalendarController.EventHandler, SearchView.OnQueryChangeListener { 51 52 private static final String TAG = SearchActivity.class.getSimpleName(); 53 54 private static final boolean DEBUG = false; 55 56 private static final int HANDLER_KEY = 0; 57 58 private static final long INITIAL_HEAP_SIZE = 4*1024*1024; 59 60 protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time"; 61 62 protected static final String BUNDLE_KEY_RESTORE_SEARCH_QUERY = 63 "key_restore_search_query"; 64 65 private static boolean mIsMultipane; 66 67 private CalendarController mController; 68 69 private EventInfoFragment mEventInfoFragment; 70 71 private long mCurrentEventId = -1; 72 73 private DeleteEventHelper mDeleteEventHelper; 74 75 private ContentResolver mContentResolver; 76 77 private ContentObserver mObserver = new ContentObserver(new Handler()) { 78 @Override 79 public boolean deliverSelfNotifications() { 80 return true; 81 } 82 83 @Override 84 public void onChange(boolean selfChange) { 85 eventsChanged(); 86 } 87 }; 88 89 @Override 90 protected void onCreate(Bundle icicle) { 91 super.onCreate(icicle); 92 // This needs to be created before setContentView 93 mController = CalendarController.getInstance(this); 94 95 mIsMultipane = (getResources().getConfiguration().screenLayout & 96 Configuration.SCREENLAYOUT_SIZE_XLARGE) != 0; 97 98 setContentView(R.layout.search); 99 100 setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); 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 mContentResolver = getContentResolver(); 107 108 // Must be the first to register because this activity can modify the 109 // list of event handlers in it's handle method. This affects who the 110 // rest of the handlers the controller dispatches to are. 111 mController.registerEventHandler(HANDLER_KEY, this); 112 113 mDeleteEventHelper = new DeleteEventHelper(this, this, 114 false /* don't exit when done */); 115 116 long millis = 0; 117 if (icicle != null) { 118 // Returns 0 if key not found 119 millis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME); 120 if (DEBUG) { 121 Log.v(TAG, "Restore value from icicle: " + millis); 122 } 123 } 124 if (millis == 0) { 125 // Didn't find a time in the bundle, look in intent or current time 126 millis = Utils.timeFromIntentInMillis(getIntent()); 127 } 128 129 Intent intent = getIntent(); 130 if (Intent.ACTION_SEARCH.equals(intent.getAction())) { 131 String query = intent.getStringExtra(SearchManager.QUERY); 132 initFragments(millis, query); 133 } 134 } 135 136 @Override 137 protected void onDestroy() { 138 super.onDestroy(); 139 CalendarController.removeInstance(this); 140 } 141 142 private void initFragments(long timeMillis, String query) { 143 FragmentManager fragmentManager = getFragmentManager(); 144 FragmentTransaction ft = fragmentManager.openTransaction(); 145 146 AgendaFragment searchResultsFragment = new AgendaFragment(timeMillis); 147 ft.replace(R.id.search_results, searchResultsFragment); 148 mController.registerEventHandler(R.id.search_results, searchResultsFragment); 149 if (!mIsMultipane) { 150 findViewById(R.id.event_info).setVisibility(View.GONE); 151 } 152 153 ft.commit(); 154 Time t = new Time(); 155 t.set(timeMillis); 156 search(query, t); 157 } 158 159 private void showEventInfo(long eventId, long startMillis, long endMillis) { 160 if (mIsMultipane) { 161 FragmentManager fragmentManager = getFragmentManager(); 162 FragmentTransaction ft = fragmentManager.openTransaction(); 163 164 mEventInfoFragment = 165 new EventInfoFragment(eventId, startMillis, endMillis); 166 ft.replace(R.id.event_info, mEventInfoFragment); 167 ft.commit(); 168 } else { 169 Intent intent = new Intent(Intent.ACTION_VIEW); 170 Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId); 171 intent.setData(eventUri); 172 intent.setClassName(this, EventInfoActivity.class.getName()); 173 intent.putExtra(EVENT_BEGIN_TIME, startMillis); 174 intent.putExtra(EVENT_END_TIME, endMillis); 175 startActivity(intent); 176 } 177 mCurrentEventId = eventId; 178 } 179 180 private void search(String searchQuery, Time goToTime) { 181 // save query in recent queries 182 SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, 183 CalendarRecentSuggestionsProvider.AUTHORITY, 184 CalendarRecentSuggestionsProvider.MODE); 185 suggestions.saveRecentQuery(searchQuery, null); 186 187 188 EventInfo searchEventInfo = new EventInfo(); 189 searchEventInfo.eventType = EventType.SEARCH; 190 searchEventInfo.query = searchQuery; 191 searchEventInfo.viewType = ViewType.AGENDA; 192 if (goToTime != null) { 193 searchEventInfo.startTime = goToTime; 194 } 195 mController.sendEvent(this, searchEventInfo); 196 } 197 198 private void deleteEvent(long eventId, long startMillis, long endMillis) { 199 mDeleteEventHelper.delete(startMillis, endMillis, eventId, -1); 200 if (mIsMultipane && mEventInfoFragment != null 201 && eventId == mCurrentEventId) { 202 FragmentManager fragmentManager = getFragmentManager(); 203 FragmentTransaction ft = fragmentManager.openTransaction(); 204 ft.remove(mEventInfoFragment); 205 ft.commit(); 206 mEventInfoFragment = null; 207 mCurrentEventId = -1; 208 } 209 } 210 211 @Override 212 public boolean onCreateOptionsMenu(Menu menu) { 213 super.onCreateOptionsMenu(menu); 214 getMenuInflater().inflate(R.menu.search_title_bar, menu); 215 SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView(); 216 searchView.setIconifiedByDefault(true); 217 searchView.setOnQueryChangeListener(this); 218 return true; 219 } 220 221 @Override 222 public boolean onOptionsItemSelected(MenuItem item) { 223 Time t = null; 224 switch (item.getItemId()) { 225 case R.id.action_today: 226 t = new Time(); 227 t.setToNow(); 228 mController.sendEvent(this, EventType.GO_TO, t, null, -1, ViewType.CURRENT); 229 return true; 230 case R.id.action_search: 231 onSearchRequested(); 232 return true; 233 case R.id.action_settings: 234 mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0); 235 return true; 236 default: 237 return false; 238 } 239 } 240 241 @Override 242 protected void onNewIntent(Intent intent) { 243 // From the Android Dev Guide: "It's important to note that when 244 // onNewIntent(Intent) is called, the Activity has not been restarted, 245 // so the getIntent() method will still return the Intent that was first 246 // received with onCreate(). This is why setIntent(Intent) is called 247 // inside onNewIntent(Intent) (just in case you call getIntent() at a 248 // later time)." 249 setIntent(intent); 250 handleIntent(intent); 251 } 252 253 private void handleIntent(Intent intent) { 254 if (Intent.ACTION_SEARCH.equals(intent.getAction())) { 255 String query = intent.getStringExtra(SearchManager.QUERY); 256 search(query, null); 257 } 258 } 259 260 @Override 261 public void onSaveInstanceState(Bundle outState) { 262 super.onSaveInstanceState(outState); 263 outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime()); 264 } 265 266 @Override 267 protected void onResume() { 268 super.onResume(); 269 mContentResolver.registerContentObserver(Events.CONTENT_URI, true, mObserver); 270 } 271 272 @Override 273 protected void onPause() { 274 super.onPause(); 275 mContentResolver.unregisterContentObserver(mObserver); 276 } 277 278// @Override 279// public boolean onKeyDown(int keyCode, KeyEvent event) { 280// switch (keyCode) { 281// case KeyEvent.KEYCODE_DEL: 282// // Delete the currently selected event (if any) 283// mAgendaListView.deleteSelectedEvent(); 284// break; 285// } 286// return super.onKeyDown(keyCode, event); 287// } 288 289 @Override 290 public void goToToday() { 291 } 292 293 @Override 294 public void goTo(Time time, boolean animate) { 295 } 296 297 @Override 298 public long getSelectedTime() { 299 return 0; 300 } 301 302 @Override 303 public boolean getAllDay() { 304 return false; 305 } 306 307 @Override 308 public void eventsChanged() { 309 mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT); 310 } 311 312 @Override 313 public long getSupportedEventTypes() { 314 return EventType.VIEW_EVENT | EventType.DELETE_EVENT; 315 } 316 317 @Override 318 public void handleEvent(EventInfo event) { 319 long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false); 320 if (event.eventType == EventType.VIEW_EVENT) { 321 showEventInfo(event.id, event.startTime.toMillis(false), endTime); 322 } else if (event.eventType == EventType.DELETE_EVENT) { 323 deleteEvent(event.id, event.startTime.toMillis(false), endTime); 324 } 325 } 326 327 @Override 328 public boolean onQueryTextChanged(String newText) { 329 return false; 330 } 331 332 @Override 333 public boolean onSubmitQuery(String query) { 334 mController.sendEvent( 335 this, EventType.SEARCH, null, null, -1, 336 ViewType.CURRENT, query, getComponentName()); 337 return false; 338 } 339} 340