• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
16 package com.android.calendar;
17 
18 import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
19 import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
20 
21 import android.app.ActionBar;
22 import android.app.Activity;
23 import android.app.FragmentManager;
24 import android.app.FragmentTransaction;
25 import android.app.SearchManager;
26 import android.content.BroadcastReceiver;
27 import android.content.ContentResolver;
28 import android.content.ContentUris;
29 import android.content.Intent;
30 import android.database.ContentObserver;
31 import android.graphics.drawable.LayerDrawable;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.provider.CalendarContract.Events;
36 import android.provider.SearchRecentSuggestions;
37 import android.text.format.Time;
38 import android.util.Log;
39 import android.view.Menu;
40 import android.view.MenuItem;
41 import android.view.MenuItem.OnActionExpandListener;
42 import android.widget.SearchView;
43 
44 import com.android.calendar.CalendarController.EventInfo;
45 import com.android.calendar.CalendarController.EventType;
46 import com.android.calendar.CalendarController.ViewType;
47 import com.android.calendar.agenda.AgendaFragment;
48 
49 public class SearchActivity extends Activity implements CalendarController.EventHandler,
50         SearchView.OnQueryTextListener, OnActionExpandListener {
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     protected static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
59 
60     protected static final String BUNDLE_KEY_RESTORE_SEARCH_QUERY =
61         "key_restore_search_query";
62 
63     // display event details to the side of the event list
64    private boolean mShowEventDetailsWithAgenda;
65    private static boolean mIsMultipane;
66 
67     private CalendarController mController;
68 
69     private EventInfoFragment mEventInfoFragment;
70 
71     private long mCurrentEventId = -1;
72 
73     private String mQuery;
74 
75     private SearchView mSearchView;
76 
77     private DeleteEventHelper mDeleteEventHelper;
78 
79     private Handler mHandler;
80     private BroadcastReceiver mTimeChangesReceiver;
81     private ContentResolver mContentResolver;
82 
83     private final ContentObserver mObserver = new ContentObserver(new Handler()) {
84         @Override
85         public boolean deliverSelfNotifications() {
86             return true;
87         }
88 
89         @Override
90         public void onChange(boolean selfChange) {
91             eventsChanged();
92         }
93     };
94 
95     // runs when a timezone was changed and updates the today icon
96     private final Runnable mTimeChangesUpdater = new Runnable() {
97         @Override
98         public void run() {
99             Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater,
100                     Utils.getTimeZone(SearchActivity.this, mTimeChangesUpdater));
101             SearchActivity.this.invalidateOptionsMenu();
102         }
103     };
104 
105     @Override
onCreate(Bundle icicle)106     protected void onCreate(Bundle icicle) {
107         super.onCreate(icicle);
108         // This needs to be created before setContentView
109         mController = CalendarController.getInstance(this);
110         mHandler = new Handler();
111 
112         mIsMultipane = Utils.getConfigBool(this, R.bool.multiple_pane_config);
113         mShowEventDetailsWithAgenda =
114             Utils.getConfigBool(this, R.bool.show_event_details_with_agenda);
115 
116         setContentView(R.layout.search);
117 
118         setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
119 
120         mContentResolver = getContentResolver();
121 
122         if (mIsMultipane) {
123             getActionBar().setDisplayOptions(
124                     ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
125         } else {
126             getActionBar().setDisplayOptions(0,
127                     ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
128         }
129 
130         // Must be the first to register because this activity can modify the
131         // list of event handlers in it's handle method. This affects who the
132         // rest of the handlers the controller dispatches to are.
133         mController.registerEventHandler(HANDLER_KEY, this);
134 
135         mDeleteEventHelper = new DeleteEventHelper(this, this,
136                 false /* don't exit when done */);
137 
138         long millis = 0;
139         if (icicle != null) {
140             // Returns 0 if key not found
141             millis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME);
142             if (DEBUG) {
143                 Log.v(TAG, "Restore value from icicle: " + millis);
144             }
145         }
146         if (millis == 0) {
147             // Didn't find a time in the bundle, look in intent or current time
148             millis = Utils.timeFromIntentInMillis(getIntent());
149         }
150 
151         Intent intent = getIntent();
152         if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
153             String query;
154             if (icicle != null && icicle.containsKey(BUNDLE_KEY_RESTORE_SEARCH_QUERY)) {
155                 query = icicle.getString(BUNDLE_KEY_RESTORE_SEARCH_QUERY);
156             } else {
157                 query = intent.getStringExtra(SearchManager.QUERY);
158             }
159             initFragments(millis, query);
160         }
161     }
162 
163     @Override
onDestroy()164     protected void onDestroy() {
165         super.onDestroy();
166         mController.deregisterAllEventHandlers();
167         CalendarController.removeInstance(this);
168     }
169 
initFragments(long timeMillis, String query)170     private void initFragments(long timeMillis, String query) {
171         FragmentManager fragmentManager = getFragmentManager();
172         FragmentTransaction ft = fragmentManager.beginTransaction();
173 
174         AgendaFragment searchResultsFragment = new AgendaFragment(timeMillis, true);
175         ft.replace(R.id.search_results, searchResultsFragment);
176         mController.registerEventHandler(R.id.search_results, searchResultsFragment);
177 
178         ft.commit();
179         Time t = new Time();
180         t.set(timeMillis);
181         search(query, t);
182     }
183 
showEventInfo(EventInfo event)184     private void showEventInfo(EventInfo event) {
185         if (mShowEventDetailsWithAgenda) {
186             FragmentManager fragmentManager = getFragmentManager();
187             FragmentTransaction ft = fragmentManager.beginTransaction();
188 
189             mEventInfoFragment = new EventInfoFragment(this, event.id,
190                     event.startTime.toMillis(false), event.endTime.toMillis(false),
191                     event.getResponse(), false, EventInfoFragment.DIALOG_WINDOW_STYLE);
192             ft.replace(R.id.agenda_event_info, mEventInfoFragment);
193             ft.commit();
194             mController.registerEventHandler(R.id.agenda_event_info, mEventInfoFragment);
195         } else {
196             Intent intent = new Intent(Intent.ACTION_VIEW);
197             Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id);
198             intent.setData(eventUri);
199             intent.setClass(this, EventInfoActivity.class);
200             intent.putExtra(EXTRA_EVENT_BEGIN_TIME,
201                     event.startTime != null ? event.startTime.toMillis(true) : -1);
202             intent.putExtra(
203                     EXTRA_EVENT_END_TIME, event.endTime != null ? event.endTime.toMillis(true) : -1);
204             startActivity(intent);
205         }
206         mCurrentEventId = event.id;
207     }
208 
search(String searchQuery, Time goToTime)209     private void search(String searchQuery, Time goToTime) {
210         // save query in recent queries
211         SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
212                 Utils.getSearchAuthority(this),
213                 CalendarRecentSuggestionsProvider.MODE);
214         suggestions.saveRecentQuery(searchQuery, null);
215 
216 
217         EventInfo searchEventInfo = new EventInfo();
218         searchEventInfo.eventType = EventType.SEARCH;
219         searchEventInfo.query = searchQuery;
220         searchEventInfo.viewType = ViewType.AGENDA;
221         if (goToTime != null) {
222             searchEventInfo.startTime = goToTime;
223         }
224         mController.sendEvent(this, searchEventInfo);
225         mQuery = searchQuery;
226         if (mSearchView != null) {
227             mSearchView.setQuery(mQuery, false);
228             mSearchView.clearFocus();
229         }
230     }
231 
deleteEvent(long eventId, long startMillis, long endMillis)232     private void deleteEvent(long eventId, long startMillis, long endMillis) {
233         mDeleteEventHelper.delete(startMillis, endMillis, eventId, -1);
234         if (mIsMultipane && mEventInfoFragment != null
235                 && eventId == mCurrentEventId) {
236             FragmentManager fragmentManager = getFragmentManager();
237             FragmentTransaction ft = fragmentManager.beginTransaction();
238             ft.remove(mEventInfoFragment);
239             ft.commit();
240             mEventInfoFragment = null;
241             mController.deregisterEventHandler(R.id.agenda_event_info);
242             mCurrentEventId = -1;
243         }
244     }
245 
246     @Override
onCreateOptionsMenu(Menu menu)247     public boolean onCreateOptionsMenu(Menu menu) {
248         super.onCreateOptionsMenu(menu);
249         getMenuInflater().inflate(R.menu.search_title_bar, menu);
250 
251         // replace the default top layer drawable of the today icon with a custom drawable
252         // that shows the day of the month of today
253         LayerDrawable icon = (LayerDrawable)menu.findItem(R.id.action_today).getIcon();
254         Utils.setTodayIcon(icon, this, Utils.getTimeZone(SearchActivity.this, mTimeChangesUpdater));
255 
256         MenuItem item = menu.findItem(R.id.action_search);
257         item.expandActionView();
258         item.setOnActionExpandListener(this);
259         mSearchView = (SearchView) item.getActionView();
260         Utils.setUpSearchView(mSearchView, this);
261         mSearchView.setQuery(mQuery, false);
262         mSearchView.clearFocus();
263 
264         return true;
265     }
266 
267     @Override
onOptionsItemSelected(MenuItem item)268     public boolean onOptionsItemSelected(MenuItem item) {
269         Time t = null;
270         switch (item.getItemId()) {
271             case R.id.action_today:
272                 t = new Time();
273                 t.setToNow();
274                 mController.sendEvent(this, EventType.GO_TO, t, null, -1, ViewType.CURRENT);
275                 return true;
276             case R.id.action_search:
277                 return false;
278             case R.id.action_settings:
279                 mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0);
280                 return true;
281             case android.R.id.home:
282                 Utils.returnToCalendarHome(this);
283                 return true;
284             default:
285                 return false;
286         }
287     }
288 
289     @Override
onNewIntent(Intent intent)290     protected void onNewIntent(Intent intent) {
291         // From the Android Dev Guide: "It's important to note that when
292         // onNewIntent(Intent) is called, the Activity has not been restarted,
293         // so the getIntent() method will still return the Intent that was first
294         // received with onCreate(). This is why setIntent(Intent) is called
295         // inside onNewIntent(Intent) (just in case you call getIntent() at a
296         // later time)."
297         setIntent(intent);
298         handleIntent(intent);
299     }
300 
handleIntent(Intent intent)301     private void handleIntent(Intent intent) {
302         if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
303             String query = intent.getStringExtra(SearchManager.QUERY);
304             search(query, null);
305         }
306     }
307 
308     @Override
onSaveInstanceState(Bundle outState)309     public void onSaveInstanceState(Bundle outState) {
310         super.onSaveInstanceState(outState);
311         outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime());
312         outState.putString(BUNDLE_KEY_RESTORE_SEARCH_QUERY, mQuery);
313     }
314 
315     @Override
onResume()316     protected void onResume() {
317         super.onResume();
318 
319         Utils.setMidnightUpdater(
320                 mHandler, mTimeChangesUpdater, Utils.getTimeZone(this, mTimeChangesUpdater));
321         // Make sure the today icon is up to date
322         invalidateOptionsMenu();
323         mTimeChangesReceiver = Utils.setTimeChangesReceiver(this, mTimeChangesUpdater);
324         mContentResolver.registerContentObserver(Events.CONTENT_URI, true, mObserver);
325         // We call this in case the user changed the time zone
326         eventsChanged();
327     }
328 
329     @Override
onPause()330     protected void onPause() {
331         super.onPause();
332         Utils.resetMidnightUpdater(mHandler, mTimeChangesUpdater);
333         Utils.clearTimeChangesReceiver(this, mTimeChangesReceiver);
334         mContentResolver.unregisterContentObserver(mObserver);
335     }
336 
337     @Override
eventsChanged()338     public void eventsChanged() {
339         mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT);
340     }
341 
342     @Override
getSupportedEventTypes()343     public long getSupportedEventTypes() {
344         return EventType.VIEW_EVENT | EventType.DELETE_EVENT;
345     }
346 
347     @Override
handleEvent(EventInfo event)348     public void handleEvent(EventInfo event) {
349         long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false);
350         if (event.eventType == EventType.VIEW_EVENT) {
351             showEventInfo(event);
352         } else if (event.eventType == EventType.DELETE_EVENT) {
353             deleteEvent(event.id, event.startTime.toMillis(false), endTime);
354         }
355     }
356 
357     @Override
onQueryTextChange(String newText)358     public boolean onQueryTextChange(String newText) {
359         return false;
360     }
361 
362     @Override
onQueryTextSubmit(String query)363     public boolean onQueryTextSubmit(String query) {
364         mQuery = query;
365         mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, 0, query,
366                 getComponentName());
367         return false;
368     }
369 
370     @Override
onMenuItemActionExpand(MenuItem item)371     public boolean onMenuItemActionExpand(MenuItem item) {
372         return true;
373     }
374 
375     @Override
onMenuItemActionCollapse(MenuItem item)376     public boolean onMenuItemActionCollapse(MenuItem item) {
377         Utils.returnToCalendarHome(this);
378         return false;
379     }
380 }
381