ListsFragment.java revision 4de59fb9ceac10ed429cd8416251329aa03ad266
1package com.android.dialer.list;
2
3import android.animation.LayoutTransition;
4import android.app.ActionBar;
5import android.app.Fragment;
6import android.app.FragmentManager;
7import android.content.Context;
8import android.content.SharedPreferences;
9import android.database.Cursor;
10import android.os.Bundle;
11import android.os.Trace;
12import android.preference.PreferenceManager;
13import android.provider.CallLog.Calls;
14import android.support.v13.app.FragmentPagerAdapter;
15import android.support.v4.view.ViewPager;
16import android.support.v4.view.ViewPager.OnPageChangeListener;
17import android.util.Log;
18import android.view.LayoutInflater;
19import android.view.View;
20import android.view.ViewGroup;
21import android.widget.AbsListView;
22import android.widget.ListView;
23
24import com.android.contacts.common.GeoUtil;
25import com.android.contacts.common.list.ViewPagerTabs;
26import com.android.contacts.commonbind.analytics.AnalyticsUtil;
27import com.android.dialer.DialtactsActivity;
28import com.android.dialer.R;
29import com.android.dialer.calllog.CallLogFragment;
30import com.android.dialer.calllog.CallLogQueryHandler;
31import com.android.dialer.calllog.ContactInfoHelper;
32import com.android.dialer.util.DialerUtils;
33import com.android.dialer.voicemail.VoicemailStatusHelper;
34import com.android.dialer.voicemail.VoicemailStatusHelperImpl;
35import com.android.dialer.widget.ActionBarController;
36import com.android.dialerbind.ObjectFactory;
37
38import java.util.ArrayList;
39
40/**
41 * Fragment that is used as the main screen of the Dialer.
42 *
43 * Contains a ViewPager that contains various contact lists like the Speed Dial list and the
44 * All Contacts list. This will also eventually contain the logic that allows sliding the
45 * ViewPager containing the lists up above the search bar and pin it against the top of the
46 * screen.
47 */
48public class ListsFragment extends Fragment
49        implements ViewPager.OnPageChangeListener, CallLogQueryHandler.Listener {
50
51    private static final boolean DEBUG = DialtactsActivity.DEBUG;
52    private static final String TAG = "ListsFragment";
53
54    public static final int TAB_INDEX_SPEED_DIAL = 0;
55    public static final int TAB_INDEX_HISTORY = 1;
56    public static final int TAB_INDEX_ALL_CONTACTS = 2;
57    public static final int TAB_INDEX_VOICEMAIL = 3;
58
59    public static final int TAB_COUNT_DEFAULT = 3;
60    public static final int TAB_COUNT_WITH_VOICEMAIL = 4;
61
62    private static final String PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER =
63            "has_active_voicemail_provider";
64
65    public interface HostInterface {
66        public ActionBarController getActionBarController();
67    }
68
69    private ActionBar mActionBar;
70    private ViewPager mViewPager;
71    private ViewPagerTabs mViewPagerTabs;
72    private ViewPagerAdapter mViewPagerAdapter;
73    private RemoveView mRemoveView;
74    private View mRemoveViewContent;
75
76    private SpeedDialFragment mSpeedDialFragment;
77    private CallLogFragment mHistoryFragment;
78    private AllContactsFragment mAllContactsFragment;
79    private CallLogFragment mVoicemailFragment;
80
81    private SharedPreferences mPrefs;
82    private boolean mHasActiveVoicemailProvider;
83    private boolean mHasFetchedVoicemailStatus;
84    private boolean mShowVoicemailTabAfterVoicemailStatusIsFetched;
85
86    private VoicemailStatusHelper mVoicemailStatusHelper;
87    private ArrayList<OnPageChangeListener> mOnPageChangeListeners =
88            new ArrayList<OnPageChangeListener>();
89
90    private String[] mTabTitles;
91    private int[] mTabIcons;
92
93    /**
94     * The position of the currently selected tab.
95     */
96    private int mTabIndex = TAB_INDEX_SPEED_DIAL;
97
98    public class ViewPagerAdapter extends FragmentPagerAdapter {
99        public ViewPagerAdapter(FragmentManager fm) {
100            super(fm);
101        }
102
103        @Override
104        public long getItemId(int position) {
105            return getRtlPosition(position);
106        }
107
108        @Override
109        public Fragment getItem(int position) {
110            switch (getRtlPosition(position)) {
111                case TAB_INDEX_SPEED_DIAL:
112                    mSpeedDialFragment = new SpeedDialFragment();
113                    return mSpeedDialFragment;
114                case TAB_INDEX_HISTORY:
115                    mHistoryFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL);
116                    return mHistoryFragment;
117                case TAB_INDEX_ALL_CONTACTS:
118                    mAllContactsFragment = new AllContactsFragment();
119                    return mAllContactsFragment;
120                case TAB_INDEX_VOICEMAIL:
121                    mVoicemailFragment = new CallLogFragment(Calls.VOICEMAIL_TYPE);
122                    return mVoicemailFragment;
123            }
124            throw new IllegalStateException("No fragment at position " + position);
125        }
126
127        @Override
128        public Object instantiateItem(ViewGroup container, int position) {
129            // On rotation the FragmentManager handles rotation. Therefore getItem() isn't called.
130            // Copy the fragments that the FragmentManager finds so that we can store them in
131            // instance variables for later.
132            final Fragment fragment =
133                    (Fragment) super.instantiateItem(container, position);
134            if (fragment instanceof SpeedDialFragment) {
135                mSpeedDialFragment = (SpeedDialFragment) fragment;
136            } else if (fragment instanceof CallLogFragment && position == TAB_INDEX_HISTORY) {
137                mHistoryFragment = (CallLogFragment) fragment;
138            } else if (fragment instanceof AllContactsFragment) {
139                mAllContactsFragment = (AllContactsFragment) fragment;
140            } else if (fragment instanceof CallLogFragment && position == TAB_INDEX_VOICEMAIL) {
141                mVoicemailFragment = (CallLogFragment) fragment;
142            }
143            return fragment;
144        }
145
146        @Override
147        public int getCount() {
148            return mHasActiveVoicemailProvider ? TAB_COUNT_WITH_VOICEMAIL : TAB_COUNT_DEFAULT;
149        }
150
151        @Override
152        public CharSequence getPageTitle(int position) {
153            return mTabTitles[position];
154        }
155    }
156
157    @Override
158    public void onCreate(Bundle savedInstanceState) {
159        Trace.beginSection(TAG + " onCreate");
160        super.onCreate(savedInstanceState);
161
162        Trace.beginSection(TAG + " getCurrentCountryIso");
163        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
164        Trace.endSection();
165
166        mVoicemailStatusHelper = new VoicemailStatusHelperImpl();
167        mHasFetchedVoicemailStatus = false;
168
169        mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
170        mHasActiveVoicemailProvider = mPrefs.getBoolean(
171                PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, false);
172
173        Trace.endSection();
174    }
175
176    @Override
177    public void onResume() {
178        Trace.beginSection(TAG + " onResume");
179        super.onResume();
180        mActionBar = getActivity().getActionBar();
181        if (getUserVisibleHint()) {
182            sendScreenViewForCurrentPosition();
183        }
184
185        // Fetch voicemail status to determine if we should show the voicemail tab.
186        CallLogQueryHandler callLogQueryHandler =
187                new CallLogQueryHandler(getActivity(), getActivity().getContentResolver(), this);
188        callLogQueryHandler.fetchVoicemailStatus();
189        Trace.endSection();
190    }
191
192    @Override
193    public View onCreateView(LayoutInflater inflater, ViewGroup container,
194            Bundle savedInstanceState) {
195        Trace.beginSection(TAG + " onCreateView");
196        Trace.beginSection(TAG + " inflate view");
197        final View parentView = inflater.inflate(R.layout.lists_fragment, container, false);
198        Trace.endSection();
199        Trace.beginSection(TAG + " setup views");
200        mViewPager = (ViewPager) parentView.findViewById(R.id.lists_pager);
201        mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
202        mViewPager.setAdapter(mViewPagerAdapter);
203        mViewPager.setOffscreenPageLimit(TAB_COUNT_WITH_VOICEMAIL - 1);
204        mViewPager.setOnPageChangeListener(this);
205        showTab(TAB_INDEX_SPEED_DIAL);
206
207        mTabTitles = new String[TAB_COUNT_WITH_VOICEMAIL];
208        mTabTitles[TAB_INDEX_SPEED_DIAL] = getResources().getString(R.string.tab_speed_dial);
209        mTabTitles[TAB_INDEX_HISTORY] = getResources().getString(R.string.tab_history);
210        mTabTitles[TAB_INDEX_ALL_CONTACTS] = getResources().getString(R.string.tab_all_contacts);
211        mTabTitles[TAB_INDEX_VOICEMAIL] = getResources().getString(R.string.tab_voicemail);
212
213        mTabIcons = new int[TAB_COUNT_WITH_VOICEMAIL];
214        mTabIcons[TAB_INDEX_SPEED_DIAL] = R.drawable.tab_speed_dial;
215        mTabIcons[TAB_INDEX_HISTORY] = R.drawable.tab_history;
216        mTabIcons[TAB_INDEX_ALL_CONTACTS] = R.drawable.tab_contacts;
217        mTabIcons[TAB_INDEX_VOICEMAIL] = R.drawable.tab_voicemail;
218
219        mViewPagerTabs = (ViewPagerTabs) parentView.findViewById(R.id.lists_pager_header);
220        mViewPagerTabs.setTabIcons(mTabIcons);
221        mViewPagerTabs.setViewPager(mViewPager);
222        addOnPageChangeListener(mViewPagerTabs);
223
224        mRemoveView = (RemoveView) parentView.findViewById(R.id.remove_view);
225        mRemoveViewContent = parentView.findViewById(R.id.remove_view_content);
226
227        Trace.endSection();
228        Trace.endSection();
229        return parentView;
230    }
231
232    public void addOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
233        if (!mOnPageChangeListeners.contains(onPageChangeListener)) {
234            mOnPageChangeListeners.add(onPageChangeListener);
235        }
236    }
237
238    /**
239     * Shows the tab with the specified index. If the voicemail tab index is specified, but the
240     * voicemail status hasn't been fetched, it will try to show the tab after the voicemail status
241     * has been fetched.
242     */
243    public void showTab(int index) {
244        if (index == TAB_INDEX_VOICEMAIL) {
245            if (mHasActiveVoicemailProvider) {
246                mViewPager.setCurrentItem(getRtlPosition(TAB_INDEX_VOICEMAIL));
247            } else if (!mHasFetchedVoicemailStatus) {
248                // Try to show the voicemail tab after the voicemail status returns.
249                mShowVoicemailTabAfterVoicemailStatusIsFetched = true;
250            }
251        } else {
252            mViewPager.setCurrentItem(getRtlPosition(index));
253        }
254    }
255
256    @Override
257    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
258        mTabIndex = getRtlPosition(position);
259
260        final int count = mOnPageChangeListeners.size();
261        for (int i = 0; i < count; i++) {
262            mOnPageChangeListeners.get(i).onPageScrolled(position, positionOffset,
263                    positionOffsetPixels);
264        }
265    }
266
267    @Override
268    public void onPageSelected(int position) {
269        mTabIndex = getRtlPosition(position);
270
271        // Show the tab which has been selected instead.
272        mShowVoicemailTabAfterVoicemailStatusIsFetched = false;
273
274        final int count = mOnPageChangeListeners.size();
275        for (int i = 0; i < count; i++) {
276            mOnPageChangeListeners.get(i).onPageSelected(position);
277        }
278        sendScreenViewForCurrentPosition();
279    }
280
281    @Override
282    public void onPageScrollStateChanged(int state) {
283        final int count = mOnPageChangeListeners.size();
284        for (int i = 0; i < count; i++) {
285            mOnPageChangeListeners.get(i).onPageScrollStateChanged(state);
286        }
287    }
288
289    @Override
290    public void onVoicemailStatusFetched(Cursor statusCursor) {
291        mHasFetchedVoicemailStatus = true;
292
293        if (getActivity() == null || getActivity().isFinishing()) {
294            return;
295        }
296
297        // Update mHasActiveVoicemailProvider, which controls the number of tabs displayed.
298        boolean hasActiveVoicemailProvider =
299                mVoicemailStatusHelper.getNumberActivityVoicemailSources(statusCursor) > 0;
300        if (hasActiveVoicemailProvider != mHasActiveVoicemailProvider) {
301            mHasActiveVoicemailProvider = hasActiveVoicemailProvider;
302            mViewPagerAdapter.notifyDataSetChanged();
303            mViewPagerTabs.setViewPager(mViewPager);
304
305            mPrefs.edit()
306                    .putBoolean(PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, hasActiveVoicemailProvider)
307                    .commit();
308        }
309
310        if (mHasActiveVoicemailProvider && mShowVoicemailTabAfterVoicemailStatusIsFetched) {
311            mShowVoicemailTabAfterVoicemailStatusIsFetched = false;
312            showTab(TAB_INDEX_VOICEMAIL);
313        }
314    }
315
316    @Override
317    public boolean onCallsFetched(Cursor statusCursor) {
318        // Return false; did not take ownership of cursor
319        return false;
320    }
321
322    public int getCurrentTabIndex() {
323        return mTabIndex;
324    }
325
326    public void showRemoveView(boolean show) {
327        mRemoveViewContent.setVisibility(show ? View.VISIBLE : View.GONE);
328        mRemoveView.setAlpha(show ? 0 : 1);
329        mRemoveView.animate().alpha(show ? 1 : 0).start();
330    }
331
332    public boolean shouldShowActionBar() {
333        // TODO: Update this based on scroll state.
334        return mActionBar != null;
335    }
336
337    public SpeedDialFragment getSpeedDialFragment() {
338        return mSpeedDialFragment;
339    }
340
341    public RemoveView getRemoveView() {
342        return mRemoveView;
343    }
344
345    public int getTabCount() {
346        return mViewPagerAdapter.getCount();
347    }
348
349    private int getRtlPosition(int position) {
350        if (DialerUtils.isRtl()) {
351            return mViewPagerAdapter.getCount() - 1 - position;
352        }
353        return position;
354    }
355
356    public void sendScreenViewForCurrentPosition() {
357        if (!isResumed()) {
358            return;
359        }
360
361        String fragmentName;
362        switch (getCurrentTabIndex()) {
363            case TAB_INDEX_SPEED_DIAL:
364                fragmentName = SpeedDialFragment.class.getSimpleName();
365                break;
366            case TAB_INDEX_HISTORY:
367                fragmentName = CallLogFragment.class.getSimpleName() + "#History";
368                break;
369            case TAB_INDEX_ALL_CONTACTS:
370                fragmentName = AllContactsFragment.class.getSimpleName();
371                break;
372            case TAB_INDEX_VOICEMAIL:
373                fragmentName = CallLogFragment.class.getSimpleName() + "#Voicemail";
374            default:
375                return;
376        }
377        AnalyticsUtil.sendScreenView(fragmentName, getActivity(), null);
378    }
379}
380