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