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