AllInOneActivity.java revision cb81189e4868769ea016253eca104e46df2f033a
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
17package com.android.calendar;
18
19import static android.provider.Calendar.EVENT_BEGIN_TIME;
20import static android.provider.Calendar.EVENT_END_TIME;
21
22import com.android.calendar.CalendarController.EventHandler;
23import com.android.calendar.CalendarController.EventInfo;
24import com.android.calendar.CalendarController.EventType;
25import com.android.calendar.CalendarController.ViewType;
26import com.android.calendar.agenda.AgendaFragment;
27import com.android.calendar.event.EditEventFragment;
28import com.android.calendar.selectcalendars.SelectCalendarsFragment;
29
30import android.app.ActionBar;
31import android.app.Activity;
32import android.app.Fragment;
33import android.app.FragmentTransaction;
34import android.content.ContentResolver;
35import android.content.Intent;
36import android.content.SharedPreferences;
37import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
38import android.content.res.Configuration;
39import android.database.ContentObserver;
40import android.net.Uri;
41import android.os.Bundle;
42import android.os.Handler;
43import android.provider.Calendar;
44import android.text.format.DateUtils;
45import android.text.format.Time;
46import android.util.Log;
47import android.view.Menu;
48import android.view.MenuItem;
49import android.view.View;
50import android.widget.SearchView;
51
52public class AllInOneActivity extends Activity implements EventHandler,
53        OnSharedPreferenceChangeListener, SearchView.OnQueryChangeListener {
54    private static final String TAG = "AllInOneActivity";
55    private static final boolean DEBUG = false;
56    private static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
57    private static final String BUNDLE_KEY_RESTORE_EDIT = "key_restore_edit";
58    private static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
59    private static final int HANDLER_KEY = 0;
60    private static CalendarController mController;
61    private static boolean mIsMultipane;
62    private ContentResolver mContentResolver;
63    private int mPreviousView;
64    private int mCurrentView;
65    private boolean mPaused = true;
66    private boolean mUpdateOnResume = false;
67
68    // Create an observer so that we can update the views whenever a
69    // Calendar event changes.
70    private ContentObserver mObserver = new ContentObserver(new Handler()) {
71        @Override
72        public boolean deliverSelfNotifications() {
73            return true;
74        }
75
76        @Override
77        public void onChange(boolean selfChange) {
78            eventsChanged();
79        }
80    };
81
82    @Override
83    protected void onCreate(Bundle icicle) {
84        super.onCreate(icicle);
85
86        // This needs to be created before setContentView
87        mController = CalendarController.getInstance(this);
88        // Get time from intent or icicle
89        long timeMillis;
90        if (icicle != null) {
91            timeMillis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME);
92        } else {
93            timeMillis = Utils.timeFromIntentInMillis(getIntent());
94        }
95        boolean restoreEdit = icicle != null ? icicle.getBoolean(BUNDLE_KEY_RESTORE_EDIT, false)
96                : false;
97        int viewType;
98        if (restoreEdit) {
99            viewType = ViewType.EDIT;
100        } else {
101            viewType = Utils.getViewTypeFromIntentAndSharedPref(this);
102        }
103        Time t = new Time();
104        t.set(timeMillis);
105
106        if (icicle != null && getIntent() != null) {
107            Log.d(TAG, "both, icicle:" + icicle.toString() + "  intent:" + getIntent().toString());
108        } else {
109            Log.d(TAG, "not both, icicle:" + icicle + " intent:" + getIntent());
110        }
111
112        mIsMultipane = (getResources().getConfiguration().screenLayout
113                & Configuration.SCREENLAYOUT_SIZE_XLARGE) != 0;
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        setContentView(R.layout.all_in_one);
121
122        initFragments(timeMillis, viewType, icicle);
123
124        // Listen for changes that would require this to be refreshed
125        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
126        prefs.registerOnSharedPreferenceChangeListener(this);
127
128        mContentResolver = getContentResolver();
129    }
130
131    @Override
132    protected void onResume() {
133        super.onResume();
134        mContentResolver.registerContentObserver(Calendar.Events.CONTENT_URI, true, mObserver);
135        if (mUpdateOnResume) {
136            initFragments(mController.getTime(), mController.getViewType(), null);
137            mUpdateOnResume = false;
138        }
139        mPaused = false;
140    }
141
142    @Override
143    protected void onPause() {
144        super.onPause();
145        mPaused = true;
146        mContentResolver.unregisterContentObserver(mObserver);
147        if (isFinishing()) {
148            // Stop listening for changes that would require this to be refreshed
149            SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
150            prefs.unregisterOnSharedPreferenceChangeListener(this);
151        }
152        // FRAG_TODO save highlighted days of the week;
153        if (mController.getViewType() != ViewType.EDIT) {
154            Utils.setDefaultView(this, mController.getViewType());
155        }
156    }
157
158    @Override
159    protected void onUserLeaveHint() {
160        mController.sendEvent(this, EventType.USER_HOME, null, null, -1, ViewType.CURRENT);
161        super.onUserLeaveHint();
162    }
163
164    @Override
165    public void onSaveInstanceState(Bundle outState) {
166        super.onSaveInstanceState(outState);
167
168        outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime());
169        if (mCurrentView == ViewType.EDIT) {
170            outState.putBoolean(BUNDLE_KEY_RESTORE_EDIT, true);
171            outState.putLong(BUNDLE_KEY_EVENT_ID, mController.getEventId());
172        }
173    }
174
175    @Override
176    protected void onDestroy() {
177        super.onDestroy();
178
179        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
180        prefs.unregisterOnSharedPreferenceChangeListener(this);
181        CalendarController.removeInstance(this);
182    }
183
184    private void initFragments(long timeMillis, int viewType, Bundle icicle) {
185        FragmentTransaction ft = getFragmentManager().openTransaction();
186
187        if (mIsMultipane) {
188            Fragment miniMonthFrag = new MonthFragment(false, timeMillis, true);
189            ft.replace(R.id.mini_month, miniMonthFrag);
190            mController.registerEventHandler(R.id.mini_month, (EventHandler) miniMonthFrag);
191
192            Fragment selectCalendarsFrag = new SelectCalendarsFragment();
193            ft.replace(R.id.calendar_list, selectCalendarsFrag);
194        }
195        if (!mIsMultipane || viewType == ViewType.EDIT) {
196            findViewById(R.id.mini_month).setVisibility(View.GONE);
197            findViewById(R.id.calendar_list).setVisibility(View.GONE);
198        }
199
200        EventInfo info = null;
201        if (viewType == ViewType.EDIT) {
202            mPreviousView = GeneralPreferences.getSharedPreferences(this).getInt(
203                    GeneralPreferences.KEY_START_VIEW, GeneralPreferences.DEFAULT_START_VIEW);
204
205            long eventId = -1;
206            Intent intent = getIntent();
207            Uri data = intent.getData();
208            if (data != null) {
209                try {
210                    eventId = Long.parseLong(data.getLastPathSegment());
211                } catch (NumberFormatException e) {
212                    if (DEBUG) {
213                        Log.d(TAG, "Create new event");
214                    }
215                }
216            } else if (icicle != null && icicle.containsKey(BUNDLE_KEY_EVENT_ID)) {
217                eventId = icicle.getLong(BUNDLE_KEY_EVENT_ID);
218            }
219
220            long begin = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
221            long end = intent.getLongExtra(EVENT_END_TIME, -1);
222            info = new EventInfo();
223            if (end != -1) {
224                info.endTime = new Time();
225                info.endTime.set(end);
226            }
227            if (begin != -1) {
228                info.startTime = new Time();
229                info.startTime.set(begin);
230            }
231            info.id = eventId;
232            // We set the viewtype so if the user presses back when they are
233            // done editing the controller knows we were in the Edit Event
234            // screen. Likewise for eventId
235            mController.setViewType(viewType);
236            mController.setEventId(eventId);
237        } else {
238            mPreviousView = viewType;
239        }
240        setMainPane(ft, R.id.main_pane, viewType, timeMillis, true, info);
241
242        ft.commit(); // this needs to be after setMainPane()
243
244        Time t = new Time();
245        t.set(timeMillis);
246        if (viewType != ViewType.EDIT) {
247            mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType);
248        }
249    }
250
251    @Override
252    public void onBackPressed() {
253        if (mPreviousView == mCurrentView) {
254            super.onBackPressed();
255        } else {
256            mController.sendEvent(this, EventType.GO_TO, null, null, -1, mPreviousView);
257        }
258    }
259
260    @Override
261    public boolean onCreateOptionsMenu(Menu menu) {
262        super.onCreateOptionsMenu(menu);
263
264        getMenuInflater().inflate(R.menu.all_in_one_title_bar, menu);
265
266        SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
267        searchView.setIconifiedByDefault(true);
268        searchView.setOnQueryChangeListener(this);
269
270        return true;
271    }
272
273    @Override
274    public boolean onOptionsItemSelected(MenuItem item) {
275        Time t = null;
276        int viewType = ViewType.CURRENT;
277        switch (item.getItemId()) {
278            case R.id.action_refresh:
279                mController.refreshCalendars();
280                return true;
281            case R.id.action_day:
282                viewType = ViewType.DAY;
283                break;
284            case R.id.action_week:
285                viewType = ViewType.WEEK;
286                break;
287            case R.id.action_month:
288                viewType = ViewType.MONTH;
289                break;
290            case R.id.action_today:
291                viewType = ViewType.CURRENT;
292                t = new Time();
293                t.setToNow();
294                break;
295            case R.id.action_create_event:
296                mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1, 0, 0, 0, 0);
297                return true;
298            case R.id.action_settings:
299                mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0);
300                return true;
301            default:
302                return false;
303        }
304        mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType);
305        return true;
306    }
307
308    @Override
309    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
310        if (key.equals(GeneralPreferences.KEY_WEEK_START_DAY)) {
311            if (mPaused) {
312                mUpdateOnResume = true;
313            } else {
314                initFragments(mController.getTime(), mController.getViewType(), null);
315            }
316        }
317    }
318
319    private void setMainPane(FragmentTransaction ft, int viewId, int viewType, long timeMillis,
320            boolean force, EventInfo e) {
321        if (!force && mCurrentView == viewType) {
322            return;
323        }
324
325        if (viewType != mCurrentView) {
326            // The rules for this previous view are different than the
327            // controller's and are used for intercepting the back button.
328            if (mCurrentView != ViewType.EDIT && mCurrentView > 0) {
329                mPreviousView = mCurrentView;
330            }
331            mCurrentView = viewType;
332        }
333        // Create new fragment
334        Fragment frag;
335        switch (viewType) {
336            case ViewType.AGENDA:
337                frag = new AgendaFragment(timeMillis);
338                break;
339            case ViewType.DAY:
340                frag = new DayFragment(timeMillis, 1);
341                break;
342            case ViewType.WEEK:
343                frag = new DayFragment(timeMillis, 7);
344                break;
345            case ViewType.MONTH:
346                frag = new MonthFragment(false, timeMillis, false);
347                break;
348            case ViewType.EDIT:
349                frag = new EditEventFragment(e, mPreviousView);
350                break;
351            default:
352                throw new IllegalArgumentException(
353                        "Must be Agenda, Day, Week, or Month ViewType, not " + viewType);
354        }
355
356        boolean doCommit = false;
357        if (ft == null) {
358            doCommit = true;
359            ft = getFragmentManager().openTransaction();
360        }
361
362        ft.replace(viewId, frag);
363        if (DEBUG) {
364            Log.d(TAG, "Adding handler with viewId " + viewId + " and type " + viewType);
365        }
366        // If the key is already registered this will replace it
367        mController.registerEventHandler(viewId, (EventHandler) frag);
368
369        if (doCommit) {
370            ft.commit();
371        }
372    }
373
374    private void setTitleInActionBar(EventInfo event) {
375        if (event.eventType != EventType.GO_TO) {
376            return;
377        }
378
379        long start = event.startTime.toMillis(false /* use isDst */);
380        long end = start;
381
382        if (event.endTime != null) {
383            end = event.endTime.toMillis(false /* use isDst */);
384        }
385        String msg = DateUtils.formatDateRange(this, start, end, DateUtils.FORMAT_SHOW_DATE);
386
387        ActionBar ab = getActionBar();
388        if (ab != null) {
389            ab.setTitle(msg);
390        }
391    }
392
393    @Override
394    public long getSupportedEventTypes() {
395        return EventType.GO_TO | EventType.VIEW_EVENT | EventType.EDIT_EVENT
396                | EventType.CREATE_EVENT;
397    }
398
399    @Override
400    public void handleEvent(EventInfo event) {
401        if (event.eventType == EventType.GO_TO) {
402            if (mCurrentView == ViewType.EDIT) {
403                // If we are leaving the edit view ping it so it has a chance to
404                // save if it needs to
405                EventHandler editHandler = (EventHandler) getFragmentManager().findFragmentById(
406                        R.id.main_pane);
407                editHandler.handleEvent(event);
408            }
409            // Set title bar
410            setTitleInActionBar(event);
411
412            setMainPane(null, R.id.main_pane, event.viewType, event.startTime.toMillis(false),
413                    false, event);
414
415            if (!mIsMultipane) {
416                return;
417            }
418            if (event.viewType == ViewType.MONTH) {
419                // hide minimonth and calendar frag
420                findViewById(R.id.mini_month).setVisibility(View.GONE);
421                findViewById(R.id.calendar_list).setVisibility(View.GONE);
422            } else {
423                // show minimonth and calendar frag
424                findViewById(R.id.mini_month).setVisibility(View.VISIBLE);
425                findViewById(R.id.calendar_list).setVisibility(View.VISIBLE);
426            }
427        } else if (event.eventType == EventType.VIEW_EVENT) {
428            EventInfoFragment fragment = new EventInfoFragment(
429                    event.id, event.startTime.toMillis(false), event.endTime.toMillis(false));
430            fragment.setDialogParams(event.x, event.y);
431            fragment.show(getFragmentManager(), "EventInfoFragment");
432        } else if (event.eventType == EventType.EDIT_EVENT
433                || event.eventType == EventType.CREATE_EVENT) {
434            setMainPane(null, R.id.main_pane, ViewType.EDIT, -1, true, event);
435            // hide minimonth and calendar frag
436            findViewById(R.id.mini_month).setVisibility(View.GONE);
437            findViewById(R.id.calendar_list).setVisibility(View.GONE);
438        }
439    }
440
441    @Override
442    public void eventsChanged() {
443        mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT);
444    }
445
446    @Override
447    public boolean getAllDay() {
448        return false;
449    }
450
451    @Override
452    public long getSelectedTime() {
453        return 0;
454    }
455
456    @Override
457    public void goTo(Time time, boolean animate) {
458    }
459
460    @Override
461    public void goToToday() {
462    }
463
464    @Override
465    public boolean onQueryTextChanged(String newText) {
466        return false;
467    }
468
469    @Override
470    public boolean onSubmitQuery(String query) {
471        mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, query,
472                getComponentName());
473        return false;
474    }
475}
476