ListsFragment.java revision 6a1461a86ad861b0e04333452e47cb81675459d5
1package com.android.dialer.list;
2
3import android.animation.LayoutTransition;
4import android.app.Fragment;
5import android.app.FragmentManager;
6import android.app.LoaderManager;
7import android.content.Context;
8import android.content.CursorLoader;
9import android.content.Loader;
10import android.content.SharedPreferences;
11import android.database.Cursor;
12import android.net.Uri;
13import android.os.Bundle;
14import android.provider.CallLog;
15import android.support.v13.app.FragmentPagerAdapter;
16import android.support.v4.view.ViewPager;
17import android.view.LayoutInflater;
18import android.view.View;
19import android.view.ViewGroup;
20import android.widget.LinearLayout;
21import android.widget.ListView;
22
23import com.android.contacts.common.GeoUtil;
24import com.android.dialer.DialtactsActivity;
25import android.view.View.OnClickListener;
26
27import com.android.dialer.R;
28import com.android.dialer.calllog.CallLogAdapter;
29import com.android.dialer.calllog.CallLogFragment;
30import com.android.dialer.calllog.CallLogQuery;
31import com.android.dialer.calllog.CallLogQueryHandler;
32import com.android.dialer.calllog.ContactInfoHelper;
33import com.android.dialerbind.ObjectFactory;
34
35/**
36 * Fragment that is used as the main screen of the Dialer.
37 *
38 * Contains a ViewPager that contains various contact lists like the Speed Dial list and the
39 * All Contacts list. This will also eventually contain the logic that allows sliding the
40 * ViewPager containing the lists up above the shortcut cards and pin it against the top of the
41 * screen.
42 */
43public class ListsFragment extends Fragment implements CallLogQueryHandler.Listener,
44        CallLogAdapter.CallFetcher {
45
46    private static final int TAB_INDEX_SPEED_DIAL = 0;
47    private static final int TAB_INDEX_RECENTS = 1;
48    private static final int TAB_INDEX_ALL_CONTACTS = 2;
49
50    private static final int TAB_INDEX_COUNT = 3;
51
52    private static final int MAX_RECENTS_ENTRIES = 20;
53    // Oldest recents entry to display is 2 weeks old.
54    private static final long OLDEST_RECENTS_DATE = 1000L * 60 * 60 * 24 * 14;
55
56    private static final String KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE =
57            "key_last_dismissed_call_shortcut_date";
58
59    // Used with LoaderManager
60    private static int MISSED_CALL_LOADER = 1;
61
62    public interface HostInterface {
63        public void showCallHistory();
64    }
65
66    private ViewPager mViewPager;
67    private ViewPagerAdapter mViewPagerAdapter;
68    private PhoneFavoriteFragment mSpeedDialFragment;
69    private CallLogFragment mRecentsFragment;
70    private AllContactsFragment mAllContactsFragment;
71
72    private String[] mTabTitles;
73
74    private PhoneFavoriteMergedAdapter mMergedAdapter;
75    private CallLogAdapter mCallLogAdapter;
76    private CallLogQueryHandler mCallLogQueryHandler;
77
78    /**
79     * Call shortcuts older than this date (persisted in shared preferences) will not show up in
80     * at the top of the screen
81     */
82    private long mLastCallShortcutDate = 0;
83
84    /**
85     * The date of the current call shortcut that is showing on screen.
86     */
87    private long mCurrentCallShortcutDate = 0;
88
89    private class MissedCallLogLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
90
91        @Override
92        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
93            final Uri uri = CallLog.Calls.CONTENT_URI;
94            final String[] projection = new String[] {CallLog.Calls.TYPE};
95            final String selection = CallLog.Calls.TYPE + " = " + CallLog.Calls.MISSED_TYPE +
96                    " AND " + CallLog.Calls.IS_READ + " = 0";
97            return new CursorLoader(getActivity(), uri, projection, selection, null, null);
98        }
99
100        @Override
101        public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
102            mCallLogAdapter.setMissedCalls(data);
103        }
104
105        @Override
106        public void onLoaderReset(Loader<Cursor> cursorLoader) {
107        }
108    }
109
110    public class ViewPagerAdapter extends FragmentPagerAdapter {
111        public ViewPagerAdapter(FragmentManager fm) {
112            super(fm);
113        }
114
115        @Override
116        public Fragment getItem(int position) {
117            switch (position) {
118                case TAB_INDEX_SPEED_DIAL:
119                    mSpeedDialFragment = new PhoneFavoriteFragment();
120                    return mSpeedDialFragment;
121                case TAB_INDEX_RECENTS:
122                    mRecentsFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL,
123                            MAX_RECENTS_ENTRIES, System.currentTimeMillis() - OLDEST_RECENTS_DATE);
124
125                    /*
126                     * Provide mViewPager as a parent viewgroup for the inflation of the footer,
127                     * to ensure that the footer view is inflated with the correct LayoutParams.
128                     * If root is null in
129                     * inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot),
130                     * the layout parameters specified in R.layout.recents_list_footer are not
131                     * correctly applied. The footer view is ultimately not attached to mViewPager.
132                     */
133                    final View viewFullHistoryFooter = getActivity().getLayoutInflater().inflate(
134                            R.layout.recents_list_footer, mViewPager, false);
135                    viewFullHistoryFooter.setOnClickListener(new OnClickListener() {
136                        @Override
137                        public void onClick(View v) {
138                            ((HostInterface) getActivity()).showCallHistory();
139                        }
140                    });
141                    mRecentsFragment.setFooterView(viewFullHistoryFooter);
142                    return mRecentsFragment;
143                case TAB_INDEX_ALL_CONTACTS:
144                    mAllContactsFragment = new AllContactsFragment();
145                    return mAllContactsFragment;
146            }
147            throw new IllegalStateException("No fragment at position " + position);
148        }
149
150        @Override
151        public int getCount() {
152            return TAB_INDEX_COUNT;
153        }
154
155        @Override
156        public CharSequence getPageTitle(int position) {
157            return mTabTitles[position];
158        }
159    }
160
161    @Override
162    public void onCreate(Bundle savedInstanceState) {
163        super.onCreate(savedInstanceState);
164
165        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
166                this, 1);
167        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
168        mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
169                new ContactInfoHelper(getActivity(), currentCountryIso), false, false);
170
171        mMergedAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, null,
172                mCallLogAdapter, null, null);
173    }
174
175    @Override
176    public void onStart() {
177        super.onStart();
178        getLoaderManager().initLoader(MISSED_CALL_LOADER, null, new MissedCallLogLoaderListener());
179    }
180
181    @Override
182    public void onResume() {
183        super.onResume();
184        final SharedPreferences prefs = getActivity().getSharedPreferences(
185                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
186        mLastCallShortcutDate = prefs.getLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, 0);
187
188        fetchCalls();
189        mCallLogAdapter.setLoading(true);
190    }
191
192    @Override
193    public void onPause() {
194        // Wipe the cache to refresh the call shortcut item. This is not that expensive because
195        // it only contains one item.
196        mCallLogAdapter.invalidateCache();
197        super.onPause();
198    }
199
200    @Override
201    public View onCreateView(LayoutInflater inflater, ViewGroup container,
202            Bundle savedInstanceState) {
203        final View parentView = inflater.inflate(R.layout.lists_fragment, container, false);
204        mViewPager = (ViewPager) parentView.findViewById(R.id.lists_pager);
205        mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
206        mViewPager.setAdapter(mViewPagerAdapter);
207        mViewPager.setOffscreenPageLimit(2);
208
209        mTabTitles = new String[TAB_INDEX_COUNT];
210        mTabTitles[TAB_INDEX_SPEED_DIAL] = getResources().getString(R.string.tab_speed_dial);
211        mTabTitles[TAB_INDEX_RECENTS] = getResources().getString(R.string.tab_recents);
212        mTabTitles[TAB_INDEX_ALL_CONTACTS] = getResources().getString(R.string.tab_all_contacts);
213
214        ViewPagerTabs tabs = (ViewPagerTabs) parentView.findViewById(R.id.lists_pager_header);
215        tabs.setViewPager(mViewPager);
216
217        final ListView shortcutCardsListView =
218                (ListView) parentView.findViewById(R.id.shortcut_card_list);
219        shortcutCardsListView.setAdapter(mMergedAdapter);
220
221        LayoutTransition transition = ((LinearLayout) parentView).getLayoutTransition();
222        // Turns on animations for all types of layout changes so that they occur for
223        // height changes.
224        transition.enableTransitionType(LayoutTransition.CHANGING);
225        return parentView;
226    }
227
228    @Override
229    public void onVoicemailStatusFetched(Cursor statusCursor) {
230        // no-op
231    }
232
233    @Override
234    public void onCallsFetched(Cursor cursor) {
235        mCallLogAdapter.setLoading(false);
236
237        // Save the date of the most recent call log item
238        if (cursor != null && cursor.moveToFirst()) {
239            mCurrentCallShortcutDate = cursor.getLong(CallLogQuery.DATE);
240        }
241
242        mCallLogAdapter.changeCursor(cursor);
243        mMergedAdapter.notifyDataSetChanged();
244    }
245
246    @Override
247    public void fetchCalls() {
248        mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL, mLastCallShortcutDate);
249    }
250
251    public void dismissShortcut(View view) {
252        mLastCallShortcutDate = mCurrentCallShortcutDate;
253        final SharedPreferences prefs = view.getContext().getSharedPreferences(
254                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
255        prefs.edit().putLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, mLastCallShortcutDate)
256                .apply();
257        fetchCalls();
258    }
259}
260