/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dialer.app.list;
import static com.android.dialer.app.list.DialtactsPagerAdapter.TAB_COUNT_WITH_VOICEMAIL;
import static com.android.dialer.app.list.DialtactsPagerAdapter.TAB_INDEX_ALL_CONTACTS;
import static com.android.dialer.app.list.DialtactsPagerAdapter.TAB_INDEX_HISTORY;
import static com.android.dialer.app.list.DialtactsPagerAdapter.TAB_INDEX_SPEED_DIAL;
import static com.android.dialer.app.list.DialtactsPagerAdapter.TAB_INDEX_VOICEMAIL;
import android.app.Fragment;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Trace;
import android.preference.PreferenceManager;
import android.provider.VoicemailContract;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.contacts.common.list.ViewPagerTabs;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.CallLogFragment;
import com.android.dialer.app.calllog.CallLogNotificationsService;
import com.android.dialer.app.voicemail.error.VoicemailStatusCorruptionHandler;
import com.android.dialer.app.voicemail.error.VoicemailStatusCorruptionHandler.Source;
import com.android.dialer.common.LogUtil;
import com.android.dialer.database.CallLogQueryHandler;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.nano.DialerImpression;
import com.android.dialer.logging.nano.ScreenEvent;
import com.android.dialer.speeddial.SpeedDialFragment;
import com.android.dialer.voicemailstatus.VisualVoicemailEnabledChecker;
import com.android.dialer.voicemailstatus.VoicemailStatusHelper;
import java.util.ArrayList;
/**
* Fragment that is used as the main screen of the Dialer.
*
*
Contains a ViewPager that contains various contact lists like the Speed Dial list and the All
* Contacts list. This will also eventually contain the logic that allows sliding the ViewPager
* containing the lists up above the search bar and pin it against the top of the screen.
*/
public class ListsFragment extends Fragment
implements ViewPager.OnPageChangeListener, CallLogQueryHandler.Listener {
private static final String TAG = "ListsFragment";
private ViewPager mViewPager;
private ViewPagerTabs mViewPagerTabs;
private DialtactsPagerAdapter mAdapter;
private RemoveView mRemoveView;
private View mRemoveViewContent;
private Fragment mCurrentPage;
private SharedPreferences mPrefs;
private boolean mHasFetchedVoicemailStatus;
private boolean mShowVoicemailTabAfterVoicemailStatusIsFetched;
private VoicemailStatusHelper mVoicemailStatusHelper;
private final ArrayList mOnPageChangeListeners = new ArrayList<>();
/** The position of the currently selected tab. */
private int mTabIndex = TAB_INDEX_SPEED_DIAL;
private CallLogQueryHandler mCallLogQueryHandler;
private final ContentObserver mVoicemailStatusObserver =
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
mCallLogQueryHandler.fetchVoicemailStatus();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
LogUtil.d("ListsFragment.onCreate", null);
Trace.beginSection(TAG + " onCreate");
super.onCreate(savedInstanceState);
mVoicemailStatusHelper = new VoicemailStatusHelper();
mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
Trace.endSection();
}
@Override
public void onResume() {
LogUtil.d("ListsFragment.onResume", null);
Trace.beginSection(TAG + " onResume");
super.onResume();
if (getUserVisibleHint()) {
sendScreenViewForCurrentPosition();
}
// Fetch voicemail status to determine if we should show the voicemail tab.
mCallLogQueryHandler =
new CallLogQueryHandler(getActivity(), getActivity().getContentResolver(), this);
mCallLogQueryHandler.fetchVoicemailStatus();
mCallLogQueryHandler.fetchMissedCallsUnreadCount();
Trace.endSection();
mCurrentPage = mAdapter.getItem(mViewPager.getCurrentItem());
if (mCurrentPage instanceof CallLogFragment) {
((CallLogFragment) mCurrentPage).onVisible();
}
}
@Override
public void onPause() {
LogUtil.d("ListsFragment.onPause", null);
if (mCurrentPage instanceof CallLogFragment) {
((CallLogFragment) mCurrentPage).onNotVisible();
}
super.onPause();
}
@Override
public void onDestroyView() {
super.onDestroyView();
mViewPager.removeOnPageChangeListener(this);
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LogUtil.d("ListsFragment.onCreateView", null);
Trace.beginSection(TAG + " onCreateView");
Trace.beginSection(TAG + " inflate view");
final View parentView = inflater.inflate(R.layout.lists_fragment, container, false);
Trace.endSection();
Trace.beginSection(TAG + " setup views");
String[] tabTitles = new String[TAB_COUNT_WITH_VOICEMAIL];
tabTitles[TAB_INDEX_SPEED_DIAL] = getResources().getString(R.string.tab_speed_dial);
tabTitles[TAB_INDEX_HISTORY] = getResources().getString(R.string.tab_history);
tabTitles[TAB_INDEX_ALL_CONTACTS] = getResources().getString(R.string.tab_all_contacts);
tabTitles[TAB_INDEX_VOICEMAIL] = getResources().getString(R.string.tab_voicemail);
int[] tabIcons = new int[TAB_COUNT_WITH_VOICEMAIL];
tabIcons[TAB_INDEX_SPEED_DIAL] = R.drawable.quantum_ic_grade_white_24;
tabIcons[TAB_INDEX_HISTORY] = R.drawable.quantum_ic_schedule_white_24;
tabIcons[TAB_INDEX_ALL_CONTACTS] = R.drawable.quantum_ic_people_white_24;
tabIcons[TAB_INDEX_VOICEMAIL] = R.drawable.quantum_ic_voicemail_white_24;
mViewPager = (ViewPager) parentView.findViewById(R.id.lists_pager);
mAdapter =
new DialtactsPagerAdapter(
getContext(),
getChildFragmentManager(),
tabTitles,
mPrefs.getBoolean(
VisualVoicemailEnabledChecker.PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER, false));
mViewPager.setAdapter(mAdapter);
mViewPager.setOffscreenPageLimit(TAB_COUNT_WITH_VOICEMAIL - 1);
mViewPager.addOnPageChangeListener(this);
showTab(TAB_INDEX_SPEED_DIAL);
mViewPagerTabs = (ViewPagerTabs) parentView.findViewById(R.id.lists_pager_header);
mViewPagerTabs.configureTabIcons(tabIcons);
mViewPagerTabs.setViewPager(mViewPager);
addOnPageChangeListener(mViewPagerTabs);
mRemoveView = (RemoveView) parentView.findViewById(R.id.remove_view);
mRemoveViewContent = parentView.findViewById(R.id.remove_view_content);
getActivity()
.getContentResolver()
.registerContentObserver(
VoicemailContract.Status.CONTENT_URI, true, mVoicemailStatusObserver);
Trace.endSection();
Trace.endSection();
return parentView;
}
@Override
public void onDestroy() {
getActivity().getContentResolver().unregisterContentObserver(mVoicemailStatusObserver);
super.onDestroy();
}
public void addOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
if (!mOnPageChangeListeners.contains(onPageChangeListener)) {
mOnPageChangeListeners.add(onPageChangeListener);
}
}
/**
* Shows the tab with the specified index. If the voicemail tab index is specified, but the
* voicemail status hasn't been fetched, it will try to show the tab after the voicemail status
* has been fetched.
*/
public void showTab(int index) {
if (index == TAB_INDEX_VOICEMAIL) {
if (mAdapter.hasActiveVoicemailProvider()) {
mViewPager.setCurrentItem(mAdapter.getRtlPosition(TAB_INDEX_VOICEMAIL));
} else if (!mHasFetchedVoicemailStatus) {
// Try to show the voicemail tab after the voicemail status returns.
mShowVoicemailTabAfterVoicemailStatusIsFetched = true;
}
} else if (index < getTabCount()) {
mViewPager.setCurrentItem(mAdapter.getRtlPosition(index));
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mTabIndex = mAdapter.getRtlPosition(position);
final int count = mOnPageChangeListeners.size();
for (int i = 0; i < count; i++) {
mOnPageChangeListeners.get(i).onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
@Override
public void onPageSelected(int position) {
LogUtil.i("ListsFragment.onPageSelected", "position: %d", position);
mTabIndex = mAdapter.getRtlPosition(position);
// Show the tab which has been selected instead.
mShowVoicemailTabAfterVoicemailStatusIsFetched = false;
final int count = mOnPageChangeListeners.size();
for (int i = 0; i < count; i++) {
mOnPageChangeListeners.get(i).onPageSelected(position);
}
sendScreenViewForCurrentPosition();
if (mCurrentPage instanceof CallLogFragment) {
((CallLogFragment) mCurrentPage).onNotVisible();
}
mCurrentPage = mAdapter.getItem(position);
if (mCurrentPage instanceof CallLogFragment) {
((CallLogFragment) mCurrentPage).onVisible();
}
}
@Override
public void onPageScrollStateChanged(int state) {
final int count = mOnPageChangeListeners.size();
for (int i = 0; i < count; i++) {
mOnPageChangeListeners.get(i).onPageScrollStateChanged(state);
}
}
@Override
public void onVoicemailStatusFetched(Cursor statusCursor) {
mHasFetchedVoicemailStatus = true;
if (getActivity() == null || getActivity().isFinishing()) {
return;
}
VoicemailStatusCorruptionHandler.maybeFixVoicemailStatus(
getContext(), statusCursor, Source.Activity);
// Update hasActiveVoicemailProvider, which controls the number of tabs displayed.
boolean hasActiveVoicemailProvider =
mVoicemailStatusHelper.getNumberActivityVoicemailSources(statusCursor) > 0;
if (hasActiveVoicemailProvider != mAdapter.hasActiveVoicemailProvider()) {
mAdapter.setHasActiveVoicemailProvider(hasActiveVoicemailProvider);
mAdapter.notifyDataSetChanged();
if (hasActiveVoicemailProvider) {
Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_TAB_VISIBLE);
mViewPagerTabs.updateTab(TAB_INDEX_VOICEMAIL);
} else {
mViewPagerTabs.removeTab(TAB_INDEX_VOICEMAIL);
mAdapter.removeVoicemailFragment(getChildFragmentManager());
}
mPrefs
.edit()
.putBoolean(
VisualVoicemailEnabledChecker.PREF_KEY_HAS_ACTIVE_VOICEMAIL_PROVIDER,
hasActiveVoicemailProvider)
.apply();
}
if (hasActiveVoicemailProvider) {
mCallLogQueryHandler.fetchVoicemailUnreadCount();
}
if (mAdapter.hasActiveVoicemailProvider() && mShowVoicemailTabAfterVoicemailStatusIsFetched) {
mShowVoicemailTabAfterVoicemailStatusIsFetched = false;
showTab(TAB_INDEX_VOICEMAIL);
}
}
@Override
public void onVoicemailUnreadCountFetched(Cursor cursor) {
if (getActivity() == null || getActivity().isFinishing() || cursor == null) {
return;
}
int count = 0;
try {
count = cursor.getCount();
} finally {
cursor.close();
}
mViewPagerTabs.setUnreadCount(count, TAB_INDEX_VOICEMAIL);
mViewPagerTabs.updateTab(TAB_INDEX_VOICEMAIL);
}
@Override
public void onMissedCallsUnreadCountFetched(Cursor cursor) {
if (getActivity() == null || getActivity().isFinishing() || cursor == null) {
return;
}
int count = 0;
try {
count = cursor.getCount();
} finally {
cursor.close();
}
mViewPagerTabs.setUnreadCount(count, TAB_INDEX_HISTORY);
mViewPagerTabs.updateTab(TAB_INDEX_HISTORY);
}
@Override
public boolean onCallsFetched(Cursor statusCursor) {
// Return false; did not take ownership of cursor
return false;
}
public int getCurrentTabIndex() {
return mTabIndex;
}
/**
* External method to update unread count because the unread count changes when the user expands a
* voicemail in the call log or when the user expands an unread call in the call history tab.
*/
public void updateTabUnreadCounts() {
if (mCallLogQueryHandler != null) {
mCallLogQueryHandler.fetchMissedCallsUnreadCount();
if (mAdapter.hasActiveVoicemailProvider()) {
mCallLogQueryHandler.fetchVoicemailUnreadCount();
}
}
}
/** External method to mark all missed calls as read. */
public void markMissedCallsAsReadAndRemoveNotifications() {
if (mCallLogQueryHandler != null) {
mCallLogQueryHandler.markMissedCallsAsRead();
CallLogNotificationsService.markNewMissedCallsAsOld(getContext(), null);
}
}
public void showRemoveView(boolean show) {
mRemoveViewContent.setVisibility(show ? View.VISIBLE : View.GONE);
mRemoveView.setAlpha(show ? 0 : 1);
mRemoveView.animate().alpha(show ? 1 : 0).start();
}
public boolean hasFrequents() {
Fragment page = mAdapter.getItem(mAdapter.getRtlPosition(TAB_INDEX_SPEED_DIAL));
return page instanceof OldSpeedDialFragment
? ((OldSpeedDialFragment) page).hasFrequents()
: ((SpeedDialFragment) page).hasFrequents();
}
public RemoveView getRemoveView() {
return mRemoveView;
}
public int getTabCount() {
return mAdapter.getCount();
}
public void sendScreenViewForCurrentPosition() {
if (!isResumed()) {
return;
}
int screenType;
switch (getCurrentTabIndex()) {
case TAB_INDEX_SPEED_DIAL:
screenType = ScreenEvent.Type.SPEED_DIAL;
break;
case TAB_INDEX_HISTORY:
screenType = ScreenEvent.Type.CALL_LOG;
break;
case TAB_INDEX_ALL_CONTACTS:
screenType = ScreenEvent.Type.ALL_CONTACTS;
break;
case TAB_INDEX_VOICEMAIL:
screenType = ScreenEvent.Type.VOICEMAIL_LOG;
break;
default:
return;
}
Logger.get(getActivity()).logScreenView(screenType, getActivity());
}
}