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