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