ListsFragment.java revision bcb91d9c9539e03fdaec74bb38acecdd34552257
1619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeypackage com.android.dialer.list;
2619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
3619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.animation.LayoutTransition;
4619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.app.ActionBar;
5619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.app.Fragment;
6619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.app.FragmentManager;
7619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.app.LoaderManager;
8619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.Context;
9619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.CursorLoader;
10619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.Loader;
11619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.content.SharedPreferences;
12619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.database.Cursor;
13619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.graphics.Rect;
14619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.net.Uri;
15619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.os.Bundle;
16619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.provider.CallLog;
1728f8857b1b46bde18b85c6d3c2a63ac44c3c2e1cEvan Millarimport android.support.v13.app.FragmentPagerAdapter;
18619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport android.support.v4.view.ViewPager;
19bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.support.v4.view.ViewPager.OnPageChangeListener;
20bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.util.Log;
21bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.view.LayoutInflater;
22bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.view.View;
23bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.view.ViewGroup;
24bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikovimport android.widget.ListView;
25bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
26b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport com.android.contacts.common.GeoUtil;
27bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikovimport com.android.dialer.DialtactsActivity;
28e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
29ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeyimport android.view.View.OnClickListener;
30ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
31619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport com.android.dialer.R;
329701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onukiimport com.android.dialer.calllog.CallLogAdapter;
330bdbe752c3c0cbbef2acb4eca74642aec9195d88Makoto Onukiimport com.android.dialer.calllog.CallLogFragment;
3435997f3fdee2984b6d5373326110eda26929001aMakoto Onukiimport com.android.dialer.calllog.CallLogQuery;
35619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport com.android.dialer.calllog.CallLogQueryHandler;
36619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkeyimport com.android.dialer.calllog.ContactInfoHelper;
3772e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikovimport com.android.dialer.list.ShortcutCardsAdapter.SwipeableShortcutCard;
38b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onukiimport com.android.dialer.widget.OverlappingPaneLayout;
395dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikovimport com.android.dialer.widget.OverlappingPaneLayout.PanelSlideListener;
40b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikovimport com.android.dialerbind.ObjectFactory;
41ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey
4289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikovimport java.util.ArrayList;
4389b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
4489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov/**
45ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey * Fragment that is used as the main screen of the Dialer.
46b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki *
47bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov * Contains a ViewPager that contains various contact lists like the Speed Dial list and the
48b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki * All Contacts list. This will also eventually contain the logic that allows sliding the
4989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov * ViewPager containing the lists up above the shortcut cards and pin it against the top of the
50b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki * screen.
51b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki */
52ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkeypublic class ListsFragment extends Fragment implements CallLogQueryHandler.Listener,
53619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        CallLogAdapter.CallFetcher, ViewPager.OnPageChangeListener {
5447fd3881dfd2a21de29e917b6114974ff0a67b1bDmitri Plotnikov
55ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    private static final boolean DEBUG = DialtactsActivity.DEBUG;
5689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private static final String TAG = "ListsFragment";
5789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
58e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public static final int TAB_INDEX_SPEED_DIAL = 0;
59ca8172420c0913dff96ea607d477d8b8abfe5ddbJeff Sharkey    public static final int TAB_INDEX_RECENTS = 1;
60e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov    public static final int TAB_INDEX_ALL_CONTACTS = 2;
611d9c0e17216ff6df5f73fbc5e784b5965c5026bdJeff Sharkey
62619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static final int TAB_INDEX_COUNT = 3;
63619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
64619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private static final int MAX_RECENTS_ENTRIES = 20;
65619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    // Oldest recents entry to display is 2 weeks old.
669701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    private static final long OLDEST_RECENTS_DATE = 1000L * 60 * 60 * 24 * 14;
67619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
68400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki    private static final String KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE =
6938210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki            "key_last_dismissed_call_shortcut_date";
703a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
7138210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki    public static final float REMOVE_VIEW_SHOWN_ALPHA = 0.5f;
7238210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki    public static final float REMOVE_VIEW_HIDDEN_ALPHA = 1;
73f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro
74bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    // Used with LoaderManager
75b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    private static int MISSED_CALL_LOADER = 1;
7624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
77b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public interface HostInterface {
785dd6d5d4acb93adc05f1fde904080787f2397f51Dmitri Plotnikov        public void showCallHistory();
7924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        public int getActionBarHeight();
80619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
81619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
82619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ActionBar mActionBar;
83619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ViewPager mViewPager;
84619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ViewPagerTabs mViewPagerTabs;
85619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ViewPagerAdapter mViewPagerAdapter;
86619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ListView mShortcutCardsListView;
87619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private RemoveView mRemoveView;
88619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private View mRemoveViewContent;
89619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private SpeedDialFragment mSpeedDialFragment;
90619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private CallLogFragment mRecentsFragment;
91619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private AllContactsFragment mAllContactsFragment;
92619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ArrayList<OnPageChangeListener> mOnPageChangeListeners =
93619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            new ArrayList<OnPageChangeListener>();
94619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
95619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private String[] mTabTitles;
96619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
97619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    private ShortcutCardsAdapter mMergedAdapter;
98bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov    private CallLogAdapter mCallLogAdapter;
9989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private CallLogQueryHandler mCallLogQueryHandler;
10089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
101bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private boolean mIsPanelOpen = true;
102bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
10324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    /**
104eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee     * Call shortcuts older than this date (persisted in shared preferences) will not show up in
10524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro     * at the top of the screen
10689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov     */
10789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private long mLastCallShortcutDate = 0;
10889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
10989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    /**
11089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov     * The date of the current call shortcut that is showing on screen.
11189b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov     */
11289b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private long mCurrentCallShortcutDate = 0;
11389b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
11489b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    private class MissedCallLogLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
11589b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
116619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        @Override
117bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
118bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            final Uri uri = CallLog.Calls.CONTENT_URI;
119bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            final String[] projection = new String[] {CallLog.Calls.TYPE};
120bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            final String selection = CallLog.Calls.TYPE + " = " + CallLog.Calls.MISSED_TYPE +
121bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                    " AND " + CallLog.Calls.IS_READ + " = 0";
122bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            return new CursorLoader(getActivity(), uri, projection, selection, null, null);
123bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
124bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
125bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
126bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
127bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            mCallLogAdapter.setMissedCalls(data);
128bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
129bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
130bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
131bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public void onLoaderReset(Loader<Cursor> cursorLoader) {
132bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        }
133bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    }
134bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
135bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    private PanelSlideListener mPanelSlideListener = new PanelSlideListener() {
136bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        @Override
137bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov        public void onPanelSlide(View panel, float slideOffset) {
138bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // For every 1 percent that the panel is slid upwards, clip 1.5 percent from each edge
139bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // of the shortcut card, to achieve the animated effect of the shortcut card
140bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // rapidly shrinking and disappearing from view when the panel is slid upwards.
141bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // slideOffset is 1 when the shortcut card is fully exposed, and 0 when completely
142bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            // hidden.
143bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            float ratioCardHidden = (1 - slideOffset) * 1.5f;
144bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            if (mShortcutCardsListView.getCount() > 0) {
145bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                SwipeableShortcutCard v =
146bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                        (SwipeableShortcutCard) mShortcutCardsListView.getChildAt(0);
147bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov                v.clipCard(ratioCardHidden);
148bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov            }
149bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
150b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            if (mActionBar != null) {
151b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                // Amount of available space that is not being hidden by the bottom pane
152b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                final int topPaneHeight = (int) (slideOffset * mShortcutCardsListView.getHeight());
153b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
154b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                final int availableActionBarHeight =
155b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                        Math.min(mActionBar.getHeight(), topPaneHeight);
156b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                mActionBar.setHideOffset(mActionBar.getHeight() - availableActionBarHeight);
157b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
158b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                if (!mActionBar.isShowing()) {
159b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    mActionBar.show();
160b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                }
161b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
162b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
163b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
164b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
165b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public void onPanelOpened(View panel) {
166b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            if (DEBUG) {
167b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                Log.d(TAG, "onPanelOpened");
168b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
169b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            mIsPanelOpen = true;
170b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
171b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
172b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
173b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public void onPanelClosed(View panel) {
174b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            if (DEBUG) {
175b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                Log.d(TAG, "onPanelClosed");
176b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
177b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            mIsPanelOpen = false;
178b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
179b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    };
180b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
181b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public class ViewPagerAdapter extends FragmentPagerAdapter {
182b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public ViewPagerAdapter(FragmentManager fm) {
183b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            super(fm);
184b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
185b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
186b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
187b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public Fragment getItem(int position) {
188b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            switch (position) {
189b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                case TAB_INDEX_SPEED_DIAL:
190b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    mSpeedDialFragment = new SpeedDialFragment();
191b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return mSpeedDialFragment;
192b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                case TAB_INDEX_RECENTS:
193b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    mRecentsFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL,
194b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                            MAX_RECENTS_ENTRIES, System.currentTimeMillis() - OLDEST_RECENTS_DATE);
195b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    mRecentsFragment.setHasFooterView(true);
196b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return mRecentsFragment;
197b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                case TAB_INDEX_ALL_CONTACTS:
198b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    mAllContactsFragment = new AllContactsFragment();
199b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                    return mAllContactsFragment;
200b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            }
201b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            throw new IllegalStateException("No fragment at position " + position);
202b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
203b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
204b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
205b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public int getCount() {
206b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return TAB_INDEX_COUNT;
207b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
208b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
209b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        @Override
210b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        public CharSequence getPageTitle(int position) {
211b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki            return mTabTitles[position];
212b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
213b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
214b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
215b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    @Override
216b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public void onCreate(Bundle savedInstanceState) {
217b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        super.onCreate(savedInstanceState);
218b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
219b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
220b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                this, 1);
221b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
222b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
223b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki                new ContactInfoHelper(getActivity(), currentCountryIso), null, false);
224b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
2253a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        mMergedAdapter = new ShortcutCardsAdapter(getActivity(), this, mCallLogAdapter);
2263a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    }
2273a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
2283a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    @Override
2293a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    public void onStart() {
2303a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        super.onStart();
2313a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee        getLoaderManager().initLoader(MISSED_CALL_LOADER, null, new MissedCallLogLoaderListener());
2323a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    }
2333a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee
2343a219cc3f5045bdebfcd975bf857c6ff26886a22Yorke Lee    @Override
235b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public void onResume() {
236b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        super.onResume();
2379701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        final SharedPreferences prefs = getActivity().getSharedPreferences(
2389701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
2399701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        mLastCallShortcutDate = prefs.getLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, 0);
2409701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        mActionBar = getActivity().getActionBar();
2419701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        fetchCalls();
2429701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        mCallLogAdapter.setLoading(true);
2439701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
2449701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
2459701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    @Override
2469701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public void onPause() {
2479701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        // Wipe the cache to refresh the call shortcut item. This is not that expensive because
2489701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        // it only contains one item.
2499701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        mCallLogAdapter.invalidateCache();
2509701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        super.onPause();
2519701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
2529701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
2539701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    @Override
2549701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public View onCreateView(LayoutInflater inflater, ViewGroup container,
2559701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            Bundle savedInstanceState) {
2569701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        final View parentView = inflater.inflate(R.layout.lists_fragment, container, false);
257e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        mViewPager = (ViewPager) parentView.findViewById(R.id.lists_pager);
258e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
259619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        mViewPager.setAdapter(mViewPagerAdapter);
260619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        mViewPager.setOffscreenPageLimit(2);
261619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        mViewPager.setOnPageChangeListener(this);
262619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
263619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        mTabTitles = new String[TAB_INDEX_COUNT];
264619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        mTabTitles[TAB_INDEX_SPEED_DIAL] = getResources().getString(R.string.tab_speed_dial);
265b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mTabTitles[TAB_INDEX_RECENTS] = getResources().getString(R.string.tab_recents);
266bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        mTabTitles[TAB_INDEX_ALL_CONTACTS] = getResources().getString(R.string.tab_all_contacts);
267400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki
268400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        mViewPagerTabs = (ViewPagerTabs) parentView.findViewById(R.id.lists_pager_header);
269400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        mViewPagerTabs.setViewPager(mViewPager);
270400e50c1efeb601f6162bd829fdf33e9dc5252f6Makoto Onuki        addOnPageChangeListener(mViewPagerTabs);
271619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
27224c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        mShortcutCardsListView = (ListView) parentView.findViewById(R.id.shortcut_card_list);
273eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        mShortcutCardsListView.setAdapter(mMergedAdapter);
274e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov
275619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        mRemoveView = (RemoveView) parentView.findViewById(R.id.remove_view);
276212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        mRemoveViewContent = parentView.findViewById(R.id.remove_view_content);
277212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki
278212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        setupPaneLayout((OverlappingPaneLayout) parentView);
279212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki
280212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki        return parentView;
281212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki    }
282212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki
283212975b9dbb3c164e11732b98266eb7361e27ac5Makoto Onuki    @Override
284bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov    public void onVoicemailStatusFetched(Cursor statusCursor) {
285bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov        // no-op
28635997f3fdee2984b6d5373326110eda26929001aMakoto Onuki    }
28735997f3fdee2984b6d5373326110eda26929001aMakoto Onuki
28889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    @Override
28989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    public void onCallsFetched(Cursor cursor) {
290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro        mCallLogAdapter.setLoading(false);
291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro
292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro        // Save the date of the most recent call log item
293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro        if (cursor != null && cursor.moveToFirst()) {
294f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro            mCurrentCallShortcutDate = cursor.getLong(CallLogQuery.DATE);
295f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro        }
29689b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
29789b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        mCallLogAdapter.changeCursor(cursor);
29889b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov        mMergedAdapter.notifyDataSetChanged();
29989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov    }
300bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov
301bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    @Override
302bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    public void fetchCalls() {
303b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL, mLastCallShortcutDate);
304b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
305b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
306b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    public void dismissShortcut(View view) {
307b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        mLastCallShortcutDate = mCurrentCallShortcutDate;
308b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        final SharedPreferences prefs = view.getContext().getSharedPreferences(
30989b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
31035997f3fdee2984b6d5373326110eda26929001aMakoto Onuki        prefs.edit().putLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, mLastCallShortcutDate)
31135997f3fdee2984b6d5373326110eda26929001aMakoto Onuki                .apply();
31235997f3fdee2984b6d5373326110eda26929001aMakoto Onuki        fetchCalls();
31335997f3fdee2984b6d5373326110eda26929001aMakoto Onuki    }
31435997f3fdee2984b6d5373326110eda26929001aMakoto Onuki
3159701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public void addOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
3169701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        if (!mOnPageChangeListeners.contains(onPageChangeListener)) {
3179701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            mOnPageChangeListeners.add(onPageChangeListener);
3189701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        }
3199701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
32089b7c2b6e0003b17d08002f02d6aeec9f9788c8dDmitri Plotnikov
321bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    @Override
322bf732767b4d4d7104e4723bda7d3b0eb0f909997Dmitri Plotnikov    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
323b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        final int count = mOnPageChangeListeners.size();
324e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        for (int i = 0; i < count; i++) {
325e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            mOnPageChangeListeners.get(i).onPageScrolled(position, positionOffset,
326e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov                    positionOffsetPixels);
327b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki        }
328b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    }
329b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki
330b0828df351e8b261ab36c8af37929bf3d9d6a4f9Makoto Onuki    @Override
3319701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    public void onPageSelected(int position) {
332e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov        final int count = mOnPageChangeListeners.size();
3339701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        for (int i = 0; i < count; i++) {
3349701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki            mOnPageChangeListeners.get(i).onPageSelected(position);
3359701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki        }
3369701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
3379701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki
3389701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    @Override
33972e3003a810fb4793a1513d17a40f8ab83d7d0afDmitri Plotnikov    public void onPageScrollStateChanged(int state) {
34071142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        final int count = mOnPageChangeListeners.size();
34171142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        for (int i = 0; i < count; i++) {
34271142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki            mOnPageChangeListeners.get(i).onPageScrollStateChanged(state);
34371142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        }
3449701936fadaf55ef773dd07015b35f99fd5f8a91Makoto Onuki    }
345bee1a6b2e7cbea778195890e442c9e50f2a4e6d9Dmitri Plotnikov
346c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki    public void showRemoveView(boolean show) {
347c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        mRemoveViewContent.setVisibility(show ? View.VISIBLE : View.GONE);
348c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        mRemoveView.setAlpha(show ? 0 : 1);
349c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        mRemoveView.animate().alpha(show ? 1 : 0).start();
350c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki
351c19d5519535bc05225eac5f7dfb830fda48497deMakoto Onuki        if (mShortcutCardsListView.getCount() > 0) {
352e99988b266dd1263162583e81e2b408e7329b1c8Dmitri Plotnikov            View v = mShortcutCardsListView.getChildAt(0);
353619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey            v.animate().withLayer()
354619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey                    .alpha(show ? REMOVE_VIEW_SHOWN_ALPHA : REMOVE_VIEW_HIDDEN_ALPHA)
35571142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki                    .start();
35671142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        }
35771142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    }
35871142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki
35971142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    public boolean shouldShowActionBar() {
36071142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki        return mIsPanelOpen && mActionBar != null;
36171142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki    }
36271142b333418ac7d589bd7522dad77b967f0bbe1Makoto Onuki
36324c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    public boolean isPaneOpen() {
36424c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        return mIsPanelOpen;
36524c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    }
36624c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro
36724c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro    private void setupPaneLayout(OverlappingPaneLayout paneLayout) {
36824c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        // TODO: Remove the notion of a capturable view. The entire view be slideable, once
36924c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        // the framework better supports nested scrolling.
37024c1d384b45a6d3c1cc959062a9d4308335fabbfDave Santoro        paneLayout.setCapturableView(mViewPagerTabs);
371eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        paneLayout.openPane();
372eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        paneLayout.setPanelSlideListener(mPanelSlideListener);
373eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        paneLayout.setIntermediatePinnedOffset(
374eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee                ((HostInterface) getActivity()).getActionBarHeight());
375eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee
376eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        LayoutTransition transition = paneLayout.getLayoutTransition();
377eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        // Turns on animations for all types of layout changes so that they occur for
378eeffa7edb048e785ebc665c830dc84d87f174b07Debashish Chatterjee        // height changes.
379619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        transition.enableTransitionType(LayoutTransition.CHANGING);
380619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
381619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
382619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public SpeedDialFragment getSpeedDialFragment() {
383619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return mSpeedDialFragment;
384619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
385619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey
386619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    public RemoveView getRemoveView() {
387619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey        return mRemoveView;
388619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey    }
389619871b0fb0175d75ff9336bfe5aec0b27b9bdadJeff Sharkey}
390b597adb79f1f57a24be2be09e3f45fa0f04f6f8fDmitri Plotnikov