com.tct.mail.ui.ConversationListFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.tct.mail.ui.ConversationListFragment.java

Source

/*
 * Copyright (C) 2012 Google Inc.
 * Licensed to 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.
 */
/******************************************************************************/
/* ========================================================================== */
/*     Modifications on Features list / Changes Request / Problems Report     */
/* -------------------------------------------------------------------------- */
/*    date   |        author        |         Key          |     comment      */
/* ----------|----------------------|----------------------|----------------- */
/* 05/28/2014|     zhonghua.tuo     |      FR 670064       |email search fun- */
/*           |                      |                      |ction             */
/* ----------|----------------------|----------------------|----------------- */
/* 04/12/2014|     Zhenhua.Fan      |      PR 861468       |email search can't*/
/*           |                      |                      |show empty view   */
/* ----------|----------------------|----------------------|----------------- */
/******************************************************************************/
/*
 ==========================================================================
 *HISTORY
 *
 *Tag            Date         Author        Description
 *============== ============ =============== ==============================
 *CONFLICT-20001 2014/10/24   wenggangjin    Modify the package conflict
 *BUGFIX-864636  2014/12/16   wenggangjin   [Android5.0][Email] Always freshing content in Airplane mode
 *BUGFIX-881447  2014/12/31   wenggangjin   [Email]Can't click "retry" icon
 *BUGFIX-884395  2014/1/5     junwei-xu     [Email]When drop down to refresh mails,screen continuous refresh does not stop
 *BUGFIX-901969  2015/01/20   xiaolin.li    [Android5.0][Email][Monkey][Crash]com.tct.email crashs at com.tct.mail.browse.ConversationCursor$UnderlyingCursorWrapper.getInnerUri
 *BUGFIX-898277  2015/01/21   chenyanhua    [Email]During the search interface display abnormal
 *BUGFIX-908180  2015-01-26   wenggangjin     [Monitor][Email]Flash back when double tap Email notification bar
 *BUGFIX-898211  2015/1/26    junwei-xu       [Email]Refresh all time in the Trash box even no network connect
 *BUGFIX-889859  2015/1/26    junwei-xu      [Email]Can't show 3th level folder when no single mail in 2nd level folder
 *BUGFIX-930431  2015-02-13   wenggangjin     [Monkey][Crash]com.tct.email java.lang.NullPointerException
 *BUGFIX-941160  2015-03-13   wenggangjin     [Scenario Test][Email][FC][monitor]Email force close happen after switch email account
 *BUGFIX-943354  2015-03-17   zhonghua.tuo    [Android5.0][Email] It show always freshing mail list in combined view when no network.
 *BUGFIX-942413  2015-03-17   wenggangjin     [Android5.0][Email]Can't refresh after moving email to other folder
 *BUGFIX_952327  2015-03-18   gengkexue     Corporate Email keep loading mails non stop
 *BUGFIX_958910  2015-03-26   zheng.zou     [Android5.0][Email]No "Search in Server" when the local search result is "0"
 *BUGFIX_959144  2015-03-31   gengkexue     [Android5.0][Email][Monitor] Cannot load mail in mail list.
 *BUGFIX-963257   2015/04/01  zhonghua-tuo     [Android5.0][Email]Two 'no connection" reminder.
 *BUGFIX-963963   2015/04/01  zhonghua-tuo     [Android5.0][Email]'No connection' flash twice in Sent when no network.
 *BUGFIX-971924   2015/04/01  peng-zhang     [Android5.0][Email][Monitor]Email inbox is empty when we refresh the folder.
 *BUGFIX-996904   2015/05/30  zheng.zou      [Email]multi-selection tap on title
 *BUGFIX-1013190   2015/06/04  chaozhang    [Monitor][Android5.0][Email]"Couldn't sign in" always display when enter email.
 *BUGFIX-1019276  2014/06/09  junwei-xu    [Email][SW]Email FC when search email on server
 *BUGFIX-413164   2014/07/07  xujian       [Email]Will pop up prompt 'result 0' during search a mail from server.
 *BUGFIX-425517   2014/07/07  chaozhang      [Email]Email has stopped when slide screen in email(once).
 *BUGFIX-1047784   2014/07/20  chaozhang   [Android5.0][Email] [Monkey][Crash][Monitor]com.tct.email crashed by Short Msg: java.lang.ClassCastException
 *BUGFIX-526255  2015-09-01   zheng.zou       CR:swipe to delete or star unstar email
 *BUGFIX_1111531 2015/11/12   lin-zhou     [Monkey][Crash][Email] 'com.tct.email' crashes during system monkey test
 *BUGFIX-1193902 2015/12/25   junwei-xu     [Android 6.0][Email]search no result page flashed
 *FR_1098700     2015/10/28   yanhua.chen   <18433><EM1>EMAIL
 *FEATURE-1804126 2016/03/14  tianjing.su     [Email]Show warning to user if the version of Exchange is not same with Email
 *BUGFIX-1815601 2016/03/23   rong-tang     [Email]The keyboard doesn't pop up after slide in the search screen
 *BUGFIX-1862349 2016/03/28   tao.gan     [GAPP][Monitor][Forse Close][Email]Email appears FC when open the email in outbox.
 ===========================================================================
 */
package com.tct.mail.ui;

import android.animation.LayoutTransition;
import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.widget.Toast;
import android.content.res.Resources;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.support.annotation.IdRes;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.*;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.TextView;

import com.tct.email.R;
import com.tct.emailcommon.provider.HostAuth;
import com.tct.mail.utils.LogTag;
import com.tct.mail.utils.LogUtils;
import com.tct.mail.utils.PLFUtils;
//TS: MOD by wenggangjin for CONFLICT_20001 START
//import com.google.common.collect.ImmutableList;
import com.tct.fw.google.common.collect.ImmutableList;
import com.tct.mail.ConversationListContext;
import com.tct.mail.analytics.Analytics;
import com.tct.mail.analytics.AnalyticsTimer;
import com.tct.mail.browse.ConversationCursor;
import com.tct.mail.browse.ConversationItemView;
import com.tct.mail.browse.ConversationItemViewModel;
import com.tct.mail.browse.ConversationListFooterView;
import com.tct.mail.browse.ToggleableItem;
import com.tct.mail.content.ObjectCursorLoader;
import com.tct.mail.providers.Account;
import com.tct.mail.providers.AccountObserver;
import com.tct.mail.providers.Conversation;
import com.tct.mail.providers.Folder;
import com.tct.mail.providers.FolderObserver;
import com.tct.mail.providers.Message;
import com.tct.mail.providers.Settings;
import com.tct.mail.providers.UIProvider;
import com.tct.mail.providers.UIProvider.AccountCapabilities;
import com.tct.mail.providers.UIProvider.ConversationListIcon;
import com.tct.mail.providers.UIProvider.FolderCapabilities;
import com.tct.mail.providers.UIProvider.Swipe;
import com.tct.mail.ui.SwipeableListView.ListItemSwipedListener;
import com.tct.mail.ui.SwipeableListView.ListItemsRemovedListener;
import com.tct.mail.ui.SwipeableListView.SwipeListener;
import com.tct.mail.ui.ViewMode.ModeChangeListener;
import com.tct.mail.utils.SortHelper;
import com.tct.mail.utils.Utils;
//TS: MOD by wenggangjin for CONFLICT_20001 END
import java.util.Collection;
import java.util.Date;
import java.util.List;

import static android.view.View.OnKeyListener;

//[FEATURE]-Add-BEGIN by TSCD.zhonghua.tuo,05/28/2014,FR 670064
import android.widget.Button;
import android.view.View.OnClickListener;
import android.view.ViewGroup.MarginLayoutParams;

import com.tct.emailcommon.utility.TextUtilities;

import android.database.Cursor;

import com.tct.emailcommon.provider.EmailContent;
import com.tct.emailcommon.provider.EmailContent.MessageColumns;

import android.content.Loader;

import com.tct.emailcommon.utility.Utility;

import android.net.Uri;
//[FEATURE]-Add-END by TSCD.zhonghua.tuo

//TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD_S
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

//TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD_E
/**
 * The conversation list UI component.
 */
public final class ConversationListFragment extends Fragment
        implements OnItemLongClickListener, ModeChangeListener, ListItemSwipedListener, OnRefreshListener,
        SwipeListener, OnKeyListener, AdapterView.OnItemClickListener, /*TCT:*/View.OnTouchListener {
    /** Key used to pass data to {@link ConversationListFragment}. */
    private static final String CONVERSATION_LIST_KEY = "conversation-list";
    /** Key used to keep track of the scroll state of the list. */
    private static final String LIST_STATE_KEY = "list-state";

    private static final String LOG_TAG = LogTag.getLogTag();

    //AM: peng-zhang 2015-04-23 EMAIL BUGFIX_971924 MOD_S
    private static final String STAG = "TctEmail";
    //AM: peng-zhang 2015-04-23 EMAIL BUGFIX_971924 MOD_E

    /** Key used to save the ListView choice mode, since ListView doesn't save it automatically! */
    private static final String CHOICE_MODE_KEY = "choice-mode-key";

    // True if we are on a tablet device
    private static boolean mTabletDevice;

    // Delay before displaying the loading view.
    private static int LOADING_DELAY_MS;
    // Minimum amount of time to keep the loading view displayed.
    private static int MINIMUM_LOADING_DURATION;

    /**
     * Frequency of update of timestamps. Initialized in
     * {@link #onCreate(Bundle)} and final afterwards.
     */
    private static int TIMESTAMP_UPDATE_INTERVAL = 0;

    private ControllableActivity mActivity;

    // Control state.
    private ConversationListCallbacks mCallbacks;

    private final Handler mHandler = new Handler();

    // The internal view objects.
    private SwipeableListView mListView;

    private View mSearchHeaderView;
    private TextView mSearchResultCountTextView;

    /**
     * Current Account being viewed
     */
    private Account mAccount;
    /**
     * Current folder being viewed.
     */
    private Folder mFolder;

    /**
     * A simple method to update the timestamps of conversations periodically.
     */
    private Runnable mUpdateTimestampsRunnable = null;

    private ConversationListContext mViewContext;

    private AnimatedAdapter mListAdapter;

    private ConversationListFooterView mFooterView;
    private ConversationListEmptyView mEmptyView;
    private View mLoadingView;
    private View mConversationUpdateTimeView;
    private ErrorListener mErrorListener;
    private FolderObserver mFolderObserver;
    private DataSetObserver mConversationCursorObserver;
    private ConversationListHeader mListHeader;
    //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_S
    private MyReceiver myReceiver = new MyReceiver();
    //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_E
    //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD_S
    private boolean show = true;
    //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD_E
    private ConversationSelectionSet mSelectedSet;
    private final AccountObserver mAccountObserver = new AccountObserver() {
        @Override
        public void onChanged(Account newAccount) {
            mAccount = newAccount;
            setSwipeAction();
        }
    };
    private ConversationUpdater mUpdater;
    /** Hash of the Conversation Cursor we last obtained from the controller. */
    private int mConversationCursorHash;
    // The number of items in the last known ConversationCursor
    private int mConversationCursorLastCount;
    // State variable to keep track if we just loaded a new list, used for analytics only
    // True if NO DATA has returned, false if we either partially or fully loaded the data
    private boolean mInitialCursorLoading;

    private @IdRes int mNextFocusLeftId;
    // Tracks if a onKey event was initiated from the listview (received ACTION_DOWN before
    // ACTION_UP). If not, the listview only receives ACTION_UP.
    private boolean mKeyInitiatedFromList;

    /** Duration, in milliseconds, of the CAB mode (peek icon) animation. */
    private static long sSelectionModeAnimationDuration = -1;

    // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_S
    //    private boolean notSetEmptyViewFocus = true;
    //    private boolean notSetListViewFocus = true;
    // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_E
    // Let's ensure that we are only showing one out of the three views at once
    private void showListView() {
        mListView.setVisibility(View.VISIBLE);
        mEmptyView.setVisibility(View.INVISIBLE);
        mLoadingView.setVisibility(View.INVISIBLE);
    }

    private void showEmptyView() {
        mEmptyView.setupEmptyView(mFolder, mViewContext.searchQuery, mListAdapter.getBidiFormatter());
        //TS: tao.gan 2015-12-09 EMAIL BUGFIX-1039985 MOD_S
        //Don't set listview invisible in case some UI issue,when we are showing search result list
        //TODO: only do this when we are showing search result list.
        //        mListView.setVisibility(View.INVISIBLE);
        //TS: tao.gan 2015-12-09 EMAIL BUGFIX-1039985 MOD_E
        mEmptyView.setVisibility(View.VISIBLE);
        mLoadingView.setVisibility(View.INVISIBLE);
        // TS: tao.gan 2015-09-21 EMAIL FEATURE-559893 ADD_S
        //If we show the empty view ,then the action bar should be shown
        mActivity.animateShow(null);
        // TS: tao.gan 2015-09-21 EMAIL FEATURE-559893 ADD_E
        // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_S
        //        if(notSetEmptyViewFocus){
        //            mEmptyView.setFocusable(true);
        //            mEmptyView.setFocusableInTouchMode(true);
        //            mEmptyView.requestFocus();
        //            notSetEmptyViewFocus = false;
        //            }
        // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_E
    }

    private void showLoadingView() {
        mListView.setVisibility(View.INVISIBLE);
        mEmptyView.setVisibility(View.INVISIBLE);
        mLoadingView.setVisibility(View.VISIBLE);
        // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_S
        //        mLoadingView.setFocusable(true);
        //        mLoadingView.setFocusableInTouchMode(true);
        //        mLoadingView.requestFocus();
        // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_E
    }

    private final Runnable mLoadingViewRunnable = new FragmentRunnable("LoadingRunnable", this) {
        @Override
        public void go() {
            if (!isCursorReadyToShow()) {
                mCanTakeDownLoadingView = false;
                showLoadingView();
                mHandler.removeCallbacks(mHideLoadingRunnable);
                mHandler.postDelayed(mHideLoadingRunnable, MINIMUM_LOADING_DURATION);
            }
            mLoadingViewPending = false;
        }
    };

    private final Runnable mHideLoadingRunnable = new FragmentRunnable("CancelLoading", this) {
        @Override
        public void go() {
            mCanTakeDownLoadingView = true;
            if (isCursorReadyToShow()) {
                hideLoadingViewAndShowContents();
            }
        }
    };

    // Keep track of if we are waiting for the loading view. This variable is also used to check
    // if the cursor corresponding to the current folder loaded (either partially or completely).
    private boolean mLoadingViewPending;
    private boolean mCanTakeDownLoadingView;

    /**
     * If <code>true</code>, we have restored (or attempted to restore) the list's scroll position
     * from when we were last on this conversation list.
     */
    private boolean mScrollPositionRestored = false;
    private MailSwipeRefreshLayout mSwipeRefreshWidget;

    /**
     * Constructor needs to be public to handle orientation changes and activity
     * lifecycle events.
     */
    public ConversationListFragment() {
        super();
    }

    @Override
    public void onBeginSwipe() {
        mSwipeRefreshWidget.setEnabled(false);
    }

    @Override
    public void onEndSwipe() {
        mSwipeRefreshWidget.setEnabled(true);
    }

    //[FEATURE]-Add-BEGIN by TSCD.zhonghua.tuo,05/28/2014,FR 670064
    private View mlocalSearchHeader;
    private TextView mLocalSearchHeaderText;
    private TextView mLocalSearchHeaderCount;
    private Button mLocalSearchHeaderAll;
    private Button mLocalSearchHeaderFrom;
    private Button mLocalSearchHeaderTo;
    private Button mLocalSearchHeaderSubject;
    public static int localSearchField = 0;

    private class LocalSearchListener implements OnClickListener {

        @Override
        public void onClick(View btn) {
            // TODO Auto-generated method stub
            switch (btn.getId()) {
            case R.id.local_search_all:
                localSearchField = UIProvider.LOCAL_SEARCH_ALL;
                initLocalSearchButton(mLocalSearchHeaderAll);
                break;
            case R.id.local_search_from:
                localSearchField = UIProvider.LOCAL_SEARCH_FROM;
                initLocalSearchButton(mLocalSearchHeaderFrom);
                break;
            case R.id.local_search_to:
                localSearchField = UIProvider.LOCAL_SEARCH_TO;
                initLocalSearchButton(mLocalSearchHeaderTo);
                break;
            case R.id.local_search_subject:
                localSearchField = UIProvider.LOCAL_SEARCH_SUBJECT;
                initLocalSearchButton(mLocalSearchHeaderSubject);
                break;
            default:
                localSearchField = UIProvider.LOCAL_SEARCH_ALL;
                break;
            }
            reFreshLocalSearch(mViewContext.searchQuery);
        }
    }

    public void reFreshLocalSearch(String query) {
        if (mAccount.searchUri != null) {
            final Uri.Builder searchBuilder = mAccount.searchUri.buildUpon();
            searchBuilder.appendQueryParameter(UIProvider.SearchQueryParameters.QUERY, query);
            final Uri searchUri = searchBuilder.build();
            //[BUGFIX]-Mod-BEGIN by TCTNB.caixia.chen,101/07/2015,PR 893304,close cursor
            Cursor cursor = mActivity.getActivityContext().getContentResolver().query(searchUri,
                    UIProvider.FOLDERS_PROJECTION, null, null, null);
            if (cursor != null) {
                cursor.close();
            }
            //[BUGFIX]-Mod-END by TCTNB.caixia.chen
            mViewContext = ConversationListContext.forSearchQuery(mAccount, mFolder, query);
            onConversationListStatusUpdated();
            requestListRefresh();
        }
    }

    private void initLocalSearchButton(Button btn) {
        switch (btn.getId()) {
        case R.id.local_search_all:
            mLocalSearchHeaderAll
                    .setTextColor(getResources().getColorStateList(R.color.message_search_match_button));
            mLocalSearchHeaderFrom.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderTo.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderSubject.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            break;
        case R.id.local_search_from:
            mLocalSearchHeaderAll.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderFrom
                    .setTextColor(getResources().getColorStateList(R.color.message_search_match_button));
            mLocalSearchHeaderTo.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderSubject.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            break;
        case R.id.local_search_to:
            mLocalSearchHeaderAll.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderFrom.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderTo
                    .setTextColor(getResources().getColorStateList(R.color.message_search_match_button));
            mLocalSearchHeaderSubject.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            break;
        case R.id.local_search_subject:
            mLocalSearchHeaderAll.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderFrom.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderTo.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderSubject
                    .setTextColor(getResources().getColorStateList(R.color.message_search_match_button));
            break;
        default:
            mLocalSearchHeaderAll.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderFrom.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderTo.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            mLocalSearchHeaderSubject.setTextColor(getResources().getColorStateList(R.color.message_search_button));
            break;
        }
    }

    private void initLocalSearchHeader() {
        mlocalSearchHeader = mActivity.findViewById(R.id.local_search_header);
        mLocalSearchHeaderText = (TextView) mActivity.findViewById(R.id.local_search_header_text);
        mLocalSearchHeaderCount = (TextView) mActivity.findViewById(R.id.local_search_count);
        mLocalSearchHeaderAll = (Button) mActivity.findViewById(R.id.local_search_all);
        mLocalSearchHeaderFrom = (Button) mActivity.findViewById(R.id.local_search_from);
        mLocalSearchHeaderTo = (Button) mActivity.findViewById(R.id.local_search_to);
        mLocalSearchHeaderSubject = (Button) mActivity.findViewById(R.id.local_search_subject);
        mLocalSearchHeaderAll.setOnClickListener(new LocalSearchListener());
        mLocalSearchHeaderFrom.setOnClickListener(new LocalSearchListener());
        mLocalSearchHeaderTo.setOnClickListener(new LocalSearchListener());
        mLocalSearchHeaderSubject.setOnClickListener(new LocalSearchListener());
    }
    //[FEATURE]-Add-END by TSCD.zhonghua.tuo

    private class ConversationCursorObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            onConversationListStatusUpdated();
        }
    }

    /**
     * Creates a new instance of {@link ConversationListFragment}, initialized
     * to display conversation list context.
     */
    public static ConversationListFragment newInstance(ConversationListContext viewContext) {
        final ConversationListFragment fragment = new ConversationListFragment();
        final Bundle args = new Bundle(1);
        args.putBundle(CONVERSATION_LIST_KEY, viewContext.toBundle());
        fragment.setArguments(args);
        return fragment;
    }

    /**
     * Show the header if the current conversation list is showing search
     * results.
     */
    private void updateSearchResultHeader(int count) {
        if (mActivity == null || mSearchHeaderView == null) {
            return;
        }
        mSearchResultCountTextView.setText(getResources().getString(R.string.search_results_loaded, count));
    }

    //[FEATURE]-Add-BEGIN by TSCD.zhonghua.tuo,05/28/2014,FR 670064
    private void updateLocalSearchResultHeader(int count) {
        if (mActivity == null || mSearchHeaderView == null) {
            return;
        }
        // Only show the header if the context is for a search result
        final Resources res = getResources();
        final boolean showHeader = ConversationListContext.isSearchResult(mViewContext);
        LogUtils.d(LOG_TAG, "ConversationListFragment.updateSearchResultHeader(%d)", count);
        if (showHeader) {
            if (!ActionBarController.SERVICE_SEARCH_MODE) {
                mListAdapter.setQueryInfo(mViewContext.searchQuery, localSearchField);
                mlocalSearchHeader.setVisibility(View.VISIBLE);
                //mSearchStatusView.setVisibility(View.GONE);
                int marginTop = true
                        ? (int) (res.getDimension(R.dimen.notification_view_height)
                                + res.getDimension(R.dimen.local_search_header_height))
                        : 0;
                MarginLayoutParams layoutParams = (MarginLayoutParams) mListView.getLayoutParams();
                layoutParams.topMargin = marginTop;
                mListView.setLayoutParams(layoutParams);
                mLocalSearchHeaderText.setText(res.getString(R.string.search_results_header));
                mLocalSearchHeaderCount.setText(res.getString(R.string.search_results_loaded, count));
            }
        }
    }

    //[FEATURE]-Add-END by TSCD.zhonghua.tuo
    @Override
    public void onActivityCreated(Bundle savedState) {
        super.onActivityCreated(savedState);
        mLoadingViewPending = false;
        mCanTakeDownLoadingView = true;
        if (sSelectionModeAnimationDuration < 0) {
            sSelectionModeAnimationDuration = getResources().getInteger(R.integer.conv_item_view_cab_anim_duration);
        }

        // Strictly speaking, we get back an android.app.Activity from
        // getActivity. However, the
        // only activity creating a ConversationListContext is a MailActivity
        // which is of type
        // ControllableActivity, so this cast should be safe. If this cast
        // fails, some other
        // activity is creating ConversationListFragments. This activity must be
        // of type
        // ControllableActivity.
        final Activity activity = getActivity();
        if (!(activity instanceof ControllableActivity)) {
            LogUtils.e(LOG_TAG, "ConversationListFragment expects only a ControllableActivity to"
                    + "create it. Cannot proceed.");
        }
        mActivity = (ControllableActivity) activity;
        // Since we now have a controllable activity, load the account from it,
        // and register for
        // future account changes.
        mAccount = mAccountObserver.initialize(mActivity.getAccountController());
        mCallbacks = mActivity.getListHandler();
        mErrorListener = mActivity.getErrorListener();
        // Start off with the current state of the folder being viewed.
        final LayoutInflater inflater = LayoutInflater.from(mActivity.getActivityContext());
        mFooterView = (ConversationListFooterView) inflater.inflate(R.layout.conversation_list_footer_view, null);
        mFooterView.setClickListener(mActivity);
        //TS: zhangchao 2015-06-04 EMAIL BUGFIX_1013190 DEL_S
        //NOTE:Use the orginal code to control the behavior.
        //TS: tuo-zhonghua 2015-04-01 EMAIL BUGFIX_963257,963963 ADD_S
        //mFooterView.setErrorListener(mErrorListener);
        //TS: tuo-zhonghua 2015-04-01 EMAIL BUGFIX_963257,963963 ADD_E
        //TS: zhangchao 2015-06-04 EMAIL BUGFIX_1013190 DEL_E
        final ConversationCursor conversationCursor = getConversationListCursor();
        final LoaderManager manager = getLoaderManager();

        // TODO: These special views are always created, doesn't matter whether they will
        // be shown or not, as we add more views this will get more expensive. Given these are
        // tips that are only shown once to the user, we should consider creating these on demand.
        final ConversationListHelper helper = mActivity.getConversationListHelper();
        final List<ConversationSpecialItemView> specialItemViews = helper != null
                ? ImmutableList.copyOf(helper.makeConversationListSpecialViews(activity, mActivity, mAccount))
                : null;
        if (specialItemViews != null) {
            // Attach to the LoaderManager
            for (final ConversationSpecialItemView view : specialItemViews) {
                view.bindFragment(manager, savedState);
            }
        }

        mListAdapter = new AnimatedAdapter(mActivity.getApplicationContext(), conversationCursor,
                mActivity.getSelectedSet(), mActivity, mListView, specialItemViews);
        mListAdapter.addFooter(mFooterView);

        // TS: tao.gan 2015-09-21 EMAIL FEATURE-559893 ADD_S
        //Add the list header in case of overlap phenomenon
        mListHeader = new ConversationListHeader(activity);
        mListAdapter.addHeader(mListHeader);

        // TS: tao.gan 2015-09-21 EMAIL FEATURE-559893 ADD_E
        // Show search result header only if we are in search mode
        final boolean showSearchHeader = ConversationListContext.isSearchResult(mViewContext);
        if (showSearchHeader) {
            mSearchHeaderView = inflater.inflate(R.layout.search_results_view, null);
            mSearchResultCountTextView = (TextView) mSearchHeaderView.findViewById(R.id.search_result_count_view);
            //TS: xujian 2015-07-08 EMAIL BUGFIX_413164 ADD_S
            mSearchHeaderView.setVisibility(View.GONE);
            //TS: xujian 2015-07-08 EMAIL BUGFIX_413164 ADD_E
            mListAdapter.addHeader(mSearchHeaderView);
        } else {
            //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_S
            if (hasUpdateTimeView()) {
                mListAdapter.addHeader(mConversationUpdateTimeView);
            }
            //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_E
        }

        mListView.setAdapter(mListAdapter);
        mSelectedSet = mActivity.getSelectedSet();
        mListView.setSelectionSet(mSelectedSet);
        mListAdapter.setFooterVisibility(false);
        mFolderObserver = new FolderObserver() {
            @Override
            public void onChanged(Folder newFolder) {
                onFolderUpdated(newFolder);
            }
        };
        mFolderObserver.initialize(mActivity.getFolderController());
        mConversationCursorObserver = new ConversationCursorObserver();
        mUpdater = mActivity.getConversationUpdater();
        mUpdater.registerConversationListObserver(mConversationCursorObserver);
        mTabletDevice = Utils.useTabletUI(mActivity.getApplicationContext().getResources());
        //[FEATURE]-Add-BEGIN by TSCD.zhonghua.tuo,05/28/2014,FR 670064
        // TS: xiaolin.li 2014-11-25 EMAIL READ_PLF MOD_S
        //if(mActivity.getActivityContext().getResources().getBoolean(R.bool.feature_email_search_enhance_on))
        if (PLFUtils.getBoolean(getActivity().getApplicationContext(), "feature_email_search_enhance_on"))
            // TS: xiaolin.li 2014-11-25 EMAIL READ_PLF MOD_E
            initLocalSearchHeader();
        //[FEATURE]-Add-END by TSCD.zhonghua.tuo
        // The onViewModeChanged callback doesn't get called when the mode
        // object is created, so
        // force setting the mode manually this time around.
        onViewModeChanged(mActivity.getViewMode().getMode());
        mActivity.getViewMode().addListener(this);

        if (mActivity.isFinishing()) {
            // Activity is finishing, just bail.
            return;
        }
        mConversationCursorHash = (conversationCursor == null) ? 0 : conversationCursor.hashCode();
        // Belt and suspenders here; make sure we do any necessary sync of the
        // ConversationCursor
        if (conversationCursor != null && conversationCursor.isRefreshReady()) {
            conversationCursor.sync();
        }

        // On a phone we never highlight a conversation, so the default is to select none.
        // On a tablet, we highlight a SINGLE conversation in landscape conversation view.
        int choice = getDefaultChoiceMode(mTabletDevice);
        if (savedState != null) {
            // Restore the choice mode if it was set earlier, or NONE if creating a fresh view.
            // Choice mode here represents the current conversation only. CAB mode does not rely on
            // the platform: checked state is a local variable {@link ConversationItemView#mChecked}
            choice = savedState.getInt(CHOICE_MODE_KEY, choice);
            if (savedState.containsKey(LIST_STATE_KEY)) {
                // TODO: find a better way to unset the selected item when restoring
                mListView.clearChoices();
            }
        }
        setChoiceMode(choice);

        // Show list and start loading list.
        showList();
        ToastBarOperation pendingOp = mActivity.getPendingToastOperation();
        if (pendingOp != null) {
            // Clear the pending operation
            mActivity.setPendingToastOperation(null);
            mActivity.onUndoAvailable(pendingOp);
        }
        /// TCT: register touch listener to hide keybord in search mode.    396
        mListView.setOnTouchListener(this);
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_S
        //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_S
        //        IntentFilter filter = new IntentFilter();
        //        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        //        activity.registerReceiver(myReceiver, filter);
        //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_E
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_E
    }

    /**
     * Returns the default choice mode for the list based on whether the list is displayed on tablet
     * or not.
     * @param isTablet
     * @return
     */
    private final static int getDefaultChoiceMode(boolean isTablet) {
        return isTablet ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE;
    }

    public AnimatedAdapter getAnimatedAdapter() {
        return mListAdapter;
    }

    @Override
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        // Initialize fragment constants from resources
        final Resources res = getResources();
        TIMESTAMP_UPDATE_INTERVAL = res.getInteger(R.integer.timestamp_update_interval);
        LOADING_DELAY_MS = res.getInteger(R.integer.conversationview_show_loading_delay);
        MINIMUM_LOADING_DURATION = res.getInteger(R.integer.conversationview_min_show_loading);
        mUpdateTimestampsRunnable = new Runnable() {
            @Override
            public void run() {
                mListView.invalidateViews();
                mHandler.postDelayed(mUpdateTimestampsRunnable, TIMESTAMP_UPDATE_INTERVAL);
            }
        };

        // Get the context from the arguments
        final Bundle args = getArguments();
        mViewContext = ConversationListContext.forBundle(args.getBundle(CONVERSATION_LIST_KEY));
        mAccount = mViewContext.account;

        setRetainInstance(false);
    }

    @Override
    public String toString() {
        final String s = super.toString();
        if (mViewContext == null) {
            return s;
        }
        final StringBuilder sb = new StringBuilder(s);
        sb.setLength(sb.length() - 1);
        sb.append(" mListAdapter=");
        sb.append(mListAdapter);
        sb.append(" folder=");
        sb.append(mViewContext.folder);
        sb.append("}");
        return sb.toString();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
        View rootView = inflater.inflate(R.layout.conversation_list, null);
        mEmptyView = (ConversationListEmptyView) rootView.findViewById(R.id.empty_view);
        mLoadingView = rootView.findViewById(R.id.background_view);
        mLoadingView.setVisibility(View.GONE);
        mLoadingView.findViewById(R.id.loading_progress).setVisibility(View.VISIBLE);
        mListView = (SwipeableListView) rootView.findViewById(R.id.conversation_list_view);
        mListView.setHeaderDividersEnabled(false);
        mListView.setOnItemLongClickListener(this);
        mListView.enableSwipe(mAccount.supportsCapability(AccountCapabilities.UNDO));
        mListView.setListItemSwipedListener(this);
        mListView.setSwipeListener(this);
        mListView.setOnKeyListener(this);
        mListView.setOnItemClickListener(this);
        //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_S
        mConversationUpdateTimeView = inflater.inflate(R.layout.conversation_update_time_view, null);
        //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_E
        if (mNextFocusLeftId != 0) {
            mListView.setNextFocusLeftId(mNextFocusLeftId);
        }

        // enable animateOnLayout (equivalent of setLayoutTransition) only for >=JB (b/14302062)
        if (Utils.isRunningJellybeanOrLater()) {
            ((ViewGroup) rootView.findViewById(R.id.conversation_list_parent_frame))
                    .setLayoutTransition(new LayoutTransition());
        }

        // By default let's show the list view
        showListView();

        if (savedState != null && savedState.containsKey(LIST_STATE_KEY)) {
            mListView.onRestoreInstanceState(savedState.getParcelable(LIST_STATE_KEY));
        }
        mSwipeRefreshWidget = (MailSwipeRefreshLayout) rootView.findViewById(R.id.swipe_refresh_widget);
        mSwipeRefreshWidget.setColorScheme(R.color.swipe_refresh_color1, R.color.swipe_refresh_color2,
                R.color.swipe_refresh_color3, R.color.swipe_refresh_color4);
        // TS: tao.gan 2015-09-21 EMAIL FEATURE-559893 ADD_S
        //ProgressEndTarget should twice as toolbar's height.
        setProgressEndTarget(2 * (int) getResources().getDimension(R.dimen.abc_action_bar_default_height_material));
        // TS: tao.gan 2015-09-21 EMAIL FEATURE-559893 ADD_E
        mSwipeRefreshWidget.setOnRefreshListener(this);
        mSwipeRefreshWidget.setScrollableChild(mListView);

        return rootView;
    }

    /**
     * Set the progress bar's distance to the top when refresh the list
     */
    public void setProgressEndTarget(int distance) {
        mSwipeRefreshWidget.setProgressViewEndTarget(false, distance);
    }

    /**
     * Sets the choice mode of the list view
     */
    private final void setChoiceMode(int choiceMode) {
        mListView.setChoiceMode(choiceMode);
    }

    /**
     * Tell the list to select nothing.
     */
    public final void setChoiceNone() {
        // On a phone, the default choice mode is already none, so nothing to do.
        if (!mTabletDevice) {
            return;
        }
        clearChoicesAndActivated();
        setChoiceMode(ListView.CHOICE_MODE_NONE);
    }

    /**
     * Tell the list to get out of selecting none.
     */
    public final void revertChoiceMode() {
        // On a phone, the default choice mode is always none, so nothing to do.
        if (!mTabletDevice) {
            return;
        }
        setChoiceMode(getDefaultChoiceMode(mTabletDevice));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onDestroyView() {
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_S
        //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_S
        //        getActivity().unregisterReceiver(myReceiver);
        //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_E
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_E
        // Clear the list's adapter
        mListAdapter.destroy();
        mListView.setAdapter(null);

        mActivity.getViewMode().removeListener(this);
        if (mFolderObserver != null) {
            mFolderObserver.unregisterAndDestroy();
            mFolderObserver = null;
        }
        if (mConversationCursorObserver != null) {
            mUpdater.unregisterConversationListObserver(mConversationCursorObserver);
            mConversationCursorObserver = null;
        }
        mAccountObserver.unregisterAndDestroy();
        getAnimatedAdapter().cleanup();
        super.onDestroyView();
    }

    /**
     * There are three binary variables, which determine what we do with a
     * message. checkbEnabled: Whether check boxes are enabled or not (forced
     * true on tablet) cabModeOn: Whether CAB mode is currently on or not.
     * pressType: long or short tap (There is a third possibility: phone or
     * tablet, but they have <em>identical</em> behavior) The matrix of
     * possibilities is:
     * <p>
     * Long tap: Always toggle selection of conversation. If CAB mode is not
     * started, then start it.
     * <pre>
     *              | Checkboxes | No Checkboxes
     *    ----------+------------+---------------
     *    CAB mode  |   Select   |     Select
     *    List mode |   Select   |     Select
     *
     * </pre>
     *
     * Reference: http://b/issue?id=6392199
     * <p>
     * {@inheritDoc}
     */
    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        // Ignore anything that is not a conversation item. Could be a footer.
        if (!(view instanceof ConversationItemView)) {
            return false;
        }
        return ((ConversationItemView) view).toggleSelectedStateOrBeginDrag();
    }

    /**
     * See the comment for
     * {@link #onItemLongClick(AdapterView, View, int, long)}.
     * <p>
     * Short tap behavior:
     *
     * <pre>
     *              | Checkboxes | No Checkboxes
     *    ----------+------------+---------------
     *    CAB mode  |    Peek    |     Select
     *    List mode |    Peek    |      Peek
     * </pre>
     *
     * Reference: http://b/issue?id=6392199
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        // TS: xiaolin.li 2015-01-20 EMAIL BUGFIX-901969 ADD_S
        if (position < 0) {
            return;
        }
        // TS: xiaolin.li 2015-01-20 EMAIL BUGFIX-901969 ADD_E
        onListItemSelected(view, position);
    }

    private void onListItemSelected(View view, int position) {
        if (view instanceof ToggleableItem) {
            //TS: zheng.zou 2015-5-30 EMAIL FEATURE_996904 MOD_S
            //            final boolean showSenderImage =
            //                    (mAccount.settings.convListIcon == ConversationListIcon.SENDER_IMAGE);
            final boolean inCabMode = !mSelectedSet.isEmpty();
            if (inCabMode) {
                //TS: zheng.zou 2015-5-30 EMAIL FEATURE_996904 MOD_E
                ((ToggleableItem) view).toggleSelectedState();
            } else {
                if (inCabMode) {
                    // this is a peek.
                    Analytics.getInstance().sendEvent("peek", null, null, mSelectedSet.size());
                }
                AnalyticsTimer.getInstance().trackStart(AnalyticsTimer.OPEN_CONV_VIEW_FROM_LIST);
                viewConversation(position);
            }
        } else {
            // Ignore anything that is not a conversation item. Could be a footer.
            // If we are using a keyboard, the highlighted item is the parent;
            // otherwise, this is a direct call from the ConverationItemView
            return;
        }
        // When a new list item is clicked, commit any existing leave behind
        // items. Wait until we have opened the desired conversation to cause
        // any position changes.
        commitDestructiveActions(Utils.useTabletUI(mActivity.getActivityContext().getResources()));
    }

    @Override
    public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
        SwipeableListView list = (SwipeableListView) view;
        // Don't need to handle ENTER because it's auto-handled as a "click".
        if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
            if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
                if (mKeyInitiatedFromList) {
                    onListItemSelected(list.getSelectedView(), list.getSelectedItemPosition());
                }
                mKeyInitiatedFromList = false;
            } else if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
                mKeyInitiatedFromList = true;
            }
            return true;
        } else if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
                final int position = list.getSelectedItemPosition();
                final Object item = getAnimatedAdapter().getItem(position);
                if (item != null && item instanceof ConversationCursor) {
                    final Conversation conv = ((ConversationCursor) item).getConversation();
                    mCallbacks.onConversationFocused(conv);
                }
            }
        }
        return false;
    }

    @Override
    public void onResume() {
        super.onResume();

        if (!isCursorReadyToShow()) {
            // If the cursor got reset, let's reset the analytics state variable and show the list
            // view since we are waiting for load again
            mInitialCursorLoading = true;
            showListView();
        }

        final ConversationCursor conversationCursor = getConversationListCursor();
        if (conversationCursor != null) {
            conversationCursor.handleNotificationActions();

            restoreLastScrolledPosition();
        }

        mSelectedSet.addObserver(mConversationSetObserver);
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_S
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);//TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD
        getActivity().registerReceiver(myReceiver, filter);
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_E
    }

    @Override
    public void onPause() {
        super.onPause();

        mSelectedSet.removeObserver(mConversationSetObserver);

        saveLastScrolledPosition();
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_S
        getActivity().unregisterReceiver(myReceiver);
        //TS: wenggangjin 2015-01-26 EMAIL BUGFIX_-908180 MOD_E
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mListView != null) {
            outState.putParcelable(LIST_STATE_KEY, mListView.onSaveInstanceState());
            outState.putInt(CHOICE_MODE_KEY, mListView.getChoiceMode());
        }

        if (mListAdapter != null) {
            mListAdapter.saveSpecialItemInstanceState(outState);
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        mHandler.postDelayed(mUpdateTimestampsRunnable, TIMESTAMP_UPDATE_INTERVAL);
        Analytics.getInstance().sendView("ConversationListFragment");
    }

    @Override
    public void onStop() {
        super.onStop();
        mHandler.removeCallbacks(mUpdateTimestampsRunnable);
    }

    @Override
    public void onViewModeChanged(int newMode) {
        if (mTabletDevice) {
            if (ViewMode.isListMode(newMode)) {
                // There are no selected conversations when in conversation list mode.
                clearChoicesAndActivated();
            }
        }
        if (mFooterView != null) {
            mFooterView.onViewModeChanged(newMode);
        }

        // Set default navigation
        if (ViewMode.isListMode(newMode)) {
            mListView.setNextFocusRightId(R.id.conversation_list_view);
            mListView.requestFocus();
        } else if (ViewMode.isConversationMode(newMode)) {
            // This would only happen in two_pane
            mListView.setNextFocusRightId(R.id.conversation_pager);
        }
    }

    public boolean isAnimating() {
        final AnimatedAdapter adapter = getAnimatedAdapter();
        if (adapter != null && adapter.isAnimating()) {
            return true;
        }
        final boolean isScrolling = (mListView != null && mListView.isScrolling());
        if (isScrolling) {
            LogUtils.i(LOG_TAG, "CLF.isAnimating=true due to scrolling");
        }
        return isScrolling;
    }

    private void clearChoicesAndActivated() {
        final int currentSelected = mListView.getCheckedItemPosition();
        if (currentSelected != ListView.INVALID_POSITION) {
            mListView.setItemChecked(mListView.getCheckedItemPosition(), false);
        }
    }

    /**
     * Handles a request to show a new conversation list, either from a search
     * query or for viewing a folder. This will initiate a data load, and hence
     * must be called on the UI thread.
     */
    private void showList() {
        mInitialCursorLoading = true;
        onFolderUpdated(mActivity.getFolderController().getFolder());
        onConversationListStatusUpdated();

        // try to get an order-of-magnitude sense for message count within folders
        // (N.B. this count currently isn't working for search folders, since their counts stream
        // in over time in pieces.)
        final Folder f = mViewContext.folder;
        if (f != null) {
            final long countLog;
            if (f.totalCount > 0) {
                countLog = (long) Math.log10(f.totalCount);
            } else {
                countLog = 0;
            }
            Analytics.getInstance().sendEvent("view_folder", f.getTypeDescription(), Long.toString(countLog),
                    f.totalCount);
        }
    }

    /**
     * View the message at the given position.
     *
     * @param position The position of the conversation in the list (as opposed to its position
     *        in the cursor)
     */
    private void viewConversation(final int position) {
        LogUtils.d(LOG_TAG, "ConversationListFragment.viewConversation(%d)", position);
        // TS: chaozhang 2015-07-20 EMAIL BUGFIX-1047784 MOD_S
        //NOTE: In monkey test,may be the clicked item is footview,so issue happen,here to avoid this.
        ConversationCursor cursor = null;
        try {
            cursor = (ConversationCursor) getAnimatedAdapter().getItem(position);
        } catch (ClassCastException e) {
            LogUtils.e(LOG_TAG,
                    "ClassCastException happen,may be current clicked item is not converionsation,but footerView");
            return;
        }
        // TS: chaozhang 2015-07-20 EMAIL BUGFIX-1047784 MOD_E
        if (cursor == null) {
            LogUtils.e(LOG_TAG, "unable to open conv at cursor pos=%s cursor=%s getPositionOffset=%s", position,
                    cursor, getAnimatedAdapter().getPositionOffset(position));
            return;
        }

        final Conversation conv = cursor.getConversation();
        // TS: tao.gan 2016-03-28 EMAIL BUGFIX-1862349 ADD_S
        if (conv == null) {
            LogUtils.e(LOG_TAG, "conversation null at ConversationListFragment#viewConversation,can't view it ");
            return;
        }
        // TS: tao.gan 2016-03-28 EMAIL BUGFIX-1862349 ADD_E
        /*
         * The cursor position may be different than the position method parameter because of
         * special views in the list.
         */
        conv.position = cursor.getPosition();
        setSelected(conv.position, true);
        mCallbacks.onConversationSelected(conv, false /* inLoaderCallbacks */);
    }

    /**
     * Sets the selected conversation to the position given here.
     * @param cursorPosition The position of the conversation in the cursor (as opposed to
     * in the list)
     * @param different if the currently selected conversation is different from the one provided
     * here.  This is a difference in conversations, not a difference in positions. For example, a
     * conversation at position 2 can move to position 4 as a result of new mail.
     */
    public void setSelected(final int cursorPosition, boolean different) {
        if (mListView.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
            return;
        }

        final int position = cursorPosition + getAnimatedAdapter().getPositionOffset(cursorPosition);

        setRawSelected(position, different);
    }

    /**
     * Sets the selected conversation to the position given here.
     * @param position The position of the item in the list
     * @param different if the currently selected conversation is different from the one provided
     * here.  This is a difference in conversations, not a difference in positions. For example, a
     * conversation at position 2 can move to position 4 as a result of new mail.
     */
    public void setRawSelected(final int position, final boolean different) {
        if (mListView.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
            return;
        }

        if (different) {
            mListView.smoothScrollToPosition(position);
        }
        mListView.setItemChecked(position, true);
    }

    /**
     * Returns the cursor associated with the conversation list.
     * @return
     */
    private ConversationCursor getConversationListCursor() {
        return mCallbacks != null ? mCallbacks.getConversationListCursor() : null;
    }

    /**
     * Request a refresh of the list. No sync is carried out and none is
     * promised.
     */
    public void requestListRefresh() {
        mListAdapter.notifyDataSetChanged();
    }

    /**
     * Change the UI to delete the conversations provided and then call the
     * {@link DestructiveAction} provided here <b>after</b> the UI has been
     * updated.
     * @param conversations
     * @param action
     */
    public void requestDelete(int actionId, final Collection<Conversation> conversations,
            final DestructiveAction action) {
        for (Conversation conv : conversations) {
            conv.localDeleteOnUpdate = true;
        }
        final ListItemsRemovedListener listener = new ListItemsRemovedListener() {
            @Override
            public void onListItemsRemoved() {
                action.performAction();
            }
        };
        if (mListView.getSwipeAction() == actionId) {
            if (!mListView.destroyItems(conversations, listener)) {
                // The listView failed to destroy the items, perform the action manually
                LogUtils.e(LOG_TAG,
                        "ConversationListFragment.requestDelete: " + "listView failed to destroy items.");
                action.performAction();
            }
            return;
        }
        // Delete the local delete items (all for now) and when done,
        // update...
        mListAdapter.delete(conversations, listener);
    }

    public void onFolderUpdated(Folder folder) {
        if (!isCursorReadyToShow()) {
            // Wait a bit before showing either the empty or loading view. If the messages are
            // actually local, it's disorienting to see this appear on every folder transition.
            // If they aren't, then it will likely take more than 200 milliseconds to load, and
            // then we'll see the loading view.
            if (!mLoadingViewPending) {
                mHandler.postDelayed(mLoadingViewRunnable, LOADING_DELAY_MS);
                mLoadingViewPending = true;
            }
        }

        mFolder = folder;
        setSwipeAction();
        // Update enabled state of swipe to refresh.
        mSwipeRefreshWidget.setEnabled(!ConversationListContext.isSearchResult(mViewContext));
        //TS: chaozhang, 2015-07-14 EMAIL BUGFIX_425517 MOD_S
        //NOTE: add here to avoid NPE
        if (mFolder == null) {
            checkSyncStatus(); // AM: Kexue.Geng 2015-03-18 EMAIL BUGFIX_952327 MOD
            return;
        }
        //TS: chaozhang, 2015-07-14 EMAIL BUGFIX_425517 MOD_E
        //TS: zhonghua.tuo 2015-03-17 EMAIL BUGFIX_943354 ADD_S
        if (mFolder.refreshUri == null) {
            mSwipeRefreshWidget.setEnabled(false);
        }
        //TS: zhonghua.tuo 2015-03-17 EMAIL BUGFIX_943354 ADD_E
        //TS: junwei-xu 2014-1-5 EMAIL BUGFIX_884395 ADD_S
        //TS: wenggangjin 2015-03-13 EMAIL BUGFIX_-941160 MOD_S
        //        if(mActivity.getFolderController().getFolder().isDraft()){
        if (mActivity.getFolderController() != null && mActivity.getFolderController().getFolder() != null
                && mActivity.getFolderController().getFolder().isDraft()) {
            mSwipeRefreshWidget.setEnabled(false);
        }
        //TS: wenggangjin 2015-03-13 EMAIL BUGFIX_-941160 MOD_E
        //TS: junwei-xu 2014-1-5 EMAIL BUGFIX_884395 ADD_E
        mListAdapter.setFolder(mFolder);
        mFooterView.setFolder(mFolder);
        if (!mFolder.wasSyncSuccessful() && !mFolder.isSyncInProgress()) {
            //TS: zhangchao 2015-06-04 EMAIL BUGFIX_1013190 MOD_S
            //NOTE: Use orginal code to control the behivor.
            //TS: tuo-zhonghua 2015-04-01 EMAIL BUGFIX_963257,963963 MOD_S
            mErrorListener.onError(mFolder, false);
            //mFooterView.updateFooterStatus(3);
            //TS: tuo-zhonghua 2015-04-01 EMAIL BUGFIX_963257,963963 mod_E
            //TS: zhangchao 2015-06-04 EMAIL BUGFIX_1013190 MOD_E
        }

        // Update the sync status bar with sync results if needed
        checkSyncStatus();

        //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_S
        if (hasUpdateTimeView()) {
            if (needListHeader()) {
                updateHeaderView();
            } else {
                mListAdapter.removeHeader(mConversationUpdateTimeView);
            }
        }
        //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_E

        // Blow away conversation items cache.
        ConversationItemViewModel.onFolderUpdated(mFolder);
    }

    /**
     * Updates the footer visibility and updates the conversation cursor
     */
    public void onConversationListStatusUpdated() {
        final ConversationCursor cursor = getConversationListCursor();
        /// TCT: add params of current footer view shown state
        final boolean showFooter = mFooterView.updateStatus(cursor, mListAdapter.getFooterViewShowState());
        mListAdapter.setFooterVisibility(showFooter);
        // Also change the cursor here.
        onCursorUpdated();
        //TS: junwei-xu 2015-12-25 EMAIL BUGFIX-1193902 DEL_S
        //Note: layout xml contains empty view, we don't need set empty view to list view.
        /*
        if(cursor == null || cursor.getCount() == 0) { // AM: Kexue.Geng 2015-03-31 EMAIL BUGFIX_959144 MOD
        mListView.setEmptyView(null); //porting from PR937218
        }
        */
        //TS: junwei-xu 2015-12-25 EMAIL BUGFIX-1193902 DEL_E
        if (isCursorReadyToShow() && mCanTakeDownLoadingView) {
            LogUtils.d(STAG, "onConversationListStatusUpdated is true!"); //AM: peng-zhang 2015-04-23 EMAIL BUGFIX_971924 MOD_ADD
            hideLoadingViewAndShowContents();
        }
        /** TCT:update local search count. */
        updateLocalSearchCount(cursor);
    }

    private void hideLoadingViewAndShowContents() {
        final ConversationCursor cursor = getConversationListCursor();
        //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 MOD_S
        //        boolean showFooter = mFooterView.updateStatus(cursor);
        /// TCT: add params of current footer view shown state
        // Update the sync status bar with sync results if needed
        final boolean showFooter = mFooterView.updateStatus(cursor, mListAdapter.getFooterViewShowState());
        //        if(!show){
        //            showFooter = false;
        //        }
        //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 MOD_E
        // Update the sync status bar with sync results if needed
        checkSyncStatus();
        mListAdapter.setFooterVisibility(showFooter);
        mLoadingViewPending = false;
        mHandler.removeCallbacks(mLoadingViewRunnable);

        //AM: peng-zhang 2015-04-23 EMAIL BUGFIX_971924 MOD_S
        LogUtils.d(STAG, "cursor is null   " + (cursor != null));
        if (cursor != null) {
            LogUtils.d(STAG, "isCursorReadyToShow   " + (ConversationCursor.isCursorReadyToShow(cursor)));
        }
        LogUtils.d(STAG, "mListAdapter cursor is null   " + (mListAdapter.getCursor() == null));
        if (mListAdapter.getCursor() != null) {
            LogUtils.d(STAG, "cursor count number   " + (mListAdapter.getCursor().getCount() == 0));
        }
        LogUtils.d(STAG, "folder has children folder   " + (mFolder.hasChildren));
        LogUtils.d(STAG, "mListAdapter count number   " + (mListAdapter.getCount()));
        //AM: peng-zhang 2015-04-23 EMAIL BUGFIX_971924 MOD_E

        // Even though cursor might be empty, the list adapter might have teasers/footers.
        // So we check the list adapter count if the cursor is fully/partially loaded.
        //TS: junwei-xu 2015-12-31 EMAIL BUGFIX-1201184 MOD_S
        //Note: No need to check if it has child folder.
        //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_889859 ADD_S
        //TS: jin.dong 2016-3-17 EMAIL BUGFIX-1786313 MOD_S
        if (cursor != null && ConversationCursor.isCursorReadyToShow(cursor) && (mListAdapter.getCursor() == null
                || (mListAdapter.getCursor().getCount() == 0 && !mFolder.hasChildren))) {//[BUGFIX]-Mod by TSNJ Zhenhua.Fan,04/12/2014,PR 861468
            //TS: jin.dong 2016-3-17 EMAIL BUGFIX-1786313 MOD_E
            //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_889859 ADD_E
            //TS: junwei-xu 2015-12-31 EMAIL BUGFIX-1201184 MOD_E
            LogUtils.d(STAG, "showEmptyView!");
            showEmptyView();
        } else {
            showListView();
            //TS: xujian 2015-07-08 EMAIL BUGFIX_413164 ADD_S
            if (mSearchHeaderView != null) {
                mSearchHeaderView.setVisibility(View.VISIBLE);
            }
            //TS: xujian 2015-07-08 EMAIL BUGFIX_413164 ADD_E
            // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_S
            //            if(notSetListViewFocus){
            //                mListView.setFocusable(true);
            //                mListView.setFocusableInTouchMode(true);
            //                mListView.requestFocus();
            //                notSetListViewFocus = false;
            //                }
            // TS: chenyanhua 2015-01-21 EMAIL BUGFIX-898277 ADD_E
        }
    }

    private void setSwipeAction() {
        int swipeSetting = Settings.getSwipeSetting(mAccount.settings);
        if (swipeSetting == Swipe.DISABLED || !mAccount.supportsCapability(AccountCapabilities.UNDO)
                || (mFolder != null && (mFolder.isTrash() || mFolder.isDraft()))) { //TS: zheng.zou 2015-09-01 EMAIL BUGFIX_526255 MOD
            mListView.enableSwipe(false);
        } else {
            final int action;
            mListView.enableSwipe(true);
            if (mFolder == null) {
                action = R.id.remove_folder;
            } else {
                switch (swipeSetting) {
                // Try to respect user's setting as best as we can and default to doing nothing
                case Swipe.DELETE:
                    // Delete in Outbox means discard failed message and put it in draft
                    if (mFolder.isType(UIProvider.FolderType.OUTBOX)) {
                        action = R.id.discard_outbox;
                    } else {
                        action = R.id.delete;
                    }
                    break;
                case Swipe.ARCHIVE:
                    // Special case spam since it shouldn't remove spam folder label on swipe
                    if (mAccount.supportsCapability(AccountCapabilities.ARCHIVE) && !mFolder.isSpam()) {
                        if (mFolder.supportsCapability(FolderCapabilities.ARCHIVE)) {
                            action = R.id.archive;
                            break;
                        } else if (mFolder.supportsCapability(FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)) {
                            action = R.id.remove_folder;
                            break;
                        }
                    }

                    /*
                     * If we get here, we don't support archive, on either the account or the
                     * folder, so we want to fall through to swipe doing nothing
                     */
                    //$FALL-THROUGH$
                default:
                    mListView.enableSwipe(false);
                    action = 0; // Use default value so setSwipeAction essentially has no effect
                    break;
                }
            }
            mListView.setSwipeAction(action);
        }
        mListView.setCurrentAccount(mAccount);
        mListView.setCurrentFolder(mFolder);
    }

    /**
     * Changes the conversation cursor in the list and sets selected position if none is set.
     */
    private void onCursorUpdated() {
        LogUtils.w(LOG_TAG, "ConversationListFragment           onCursorUpdated          ");
        if (mCallbacks == null || mListAdapter == null) {
            return;
        }
        // Check against the previous cursor here and see if they are the same. If they are, then
        // do a notifyDataSetChanged.
        final ConversationCursor newCursor = mCallbacks.getConversationListCursor();
        //TS: junwei-xu 2015-06-09 EMAIL BUGFIX-1019276 MOD_S
        //Notes: if newCursor contains '%', when use LogUtils.w(),it will throws MissingFormatArgumentException,
        //so, we use Log.w() to print log.
        //LogUtils.w(LOG_TAG, "ConversationListFragment           onCursorUpdated          newCursor:" + newCursor);
        LogUtils.d(LOG_TAG, "ConversationListFragment           onCursorUpdated          newCursor:" + newCursor);
        //TS: junwei-xu 2015-06-09 EMAIL BUGFIX-1019276 MOD_E

        if (newCursor == null && mListAdapter.getCursor() != null) {
            // We're losing our cursor, so save our scroll position
            saveLastScrolledPosition();
        }
        //TS: zheng.zou 2016-1-14 EMAIL TASK_1431225 ADD_S
        if (hasUpdateTimeView()) {
            if (needListHeader()) {
                if (!mListAdapter.containsHeader(mConversationUpdateTimeView)) {
                    mListAdapter.addHeader(mConversationUpdateTimeView);
                }
                updateHeaderView();
            } else {
                mListAdapter.removeHeader(mConversationUpdateTimeView);
            }
        }
        //TS: zheng.zou 2016-1-14 EMAIL TASK_1431225 ADD_E

        mListAdapter.swapCursor(newCursor);
        // When the conversation cursor is *updated*, we get back the same instance. In that
        // situation, CursorAdapter.swapCursor() silently returns, without forcing a
        // notifyDataSetChanged(). So let's force a call to notifyDataSetChanged, since an updated
        // cursor means that the dataset has changed.
        final int newCursorHash = (newCursor == null) ? 0 : newCursor.hashCode();
        LogUtils.w(LOG_TAG,
                "ConversationListFragment           onCursorUpdated          newCursorHash:" + newCursorHash);
        LogUtils.w(LOG_TAG, "ConversationListFragment           onCursorUpdated          mConversationCursorHash:"
                + mConversationCursorHash);
        if (mConversationCursorHash == newCursorHash && mConversationCursorHash != 0) {
            LogUtils.w(LOG_TAG, "ConversationListFragment           onCursorUpdated          ");
            mListAdapter.notifyDataSetChanged();
        }
        mConversationCursorHash = newCursorHash;

        updateAnalyticsData(newCursor);
        if (newCursor != null) {
            final int newCursorCount = newCursor.getCount();
            //[FEATURE]-Mod-BEGIN by TSCD.zhonghua.tuo,05/28/2014,FR 670064
            // TS: xiaolin.li 2014-11-25 EMAIL READ_PLF MOD_S
            //if(mActivity.getActivityContext().getResources().getBoolean(R.bool.feature_email_search_enhance_on)){
            //            if(PLFUtils.getBoolean(getActivity().getApplicationContext(), "feature_email_search_enhance_on")){
            //            // TS: xiaolin.li 2014-11-25 EMAIL READ_PLF MOD_E
            //                if(ActionBarController.SERVICE_SEARCH_MODE) {
            //                    updateSearchResultHeader(newCursorCount);
            //                }else {
            //                    updateLocalSearchResultHeader(newCursorCount);
            //                }
            //            }
            //            //[BUGFIX]-Add-BEGIN by TSNJ Zhenhua.Fan,04/12/2014,PR 861468
            //            else
            //            {
            //                updateSearchResultHeader(newCursorCount);
            //            }
            // We want to update the UI with this information if either we are loaded or complete,
            // or we have a folder with a non-0 count.
            /// TCT: Show total count for remote search
            final int folderCount = mFolder != null ? mFolder.totalCount : 0;
            updateSearchResultHeader(folderCount);
            //[BUGFIX]-Add-EDN by TSNJ Zhenhua.Fan
            //[FEATURE]-Mod-END by TSCD.zhonghua.tuo
            if (newCursorCount > 0) {
                //TS: jin.dong 2016-3-7 EMAIL BUGFIX_1748590 MOD_S
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        newCursor.markContentsSeen();
                    }
                }).start();
                //TS: jin.dong 2016-3-7 EMAIL BUGFIX_1748590 MOD_E
                restoreLastScrolledPosition();
            }
        }
        //TS: zheng.zou 2016-1-14 EMAIL TASK_1431225 DEL_S
        //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_S
        //        if(hasUpdateTimeView()){
        //            updateHeaderView();
        //        }
        //TS: zheng.zou 2016-1-14 EMAIL TASK_1431225 DEL_E
        //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_E

        // If a current conversation is available, and none is selected in the list, then ask
        // the list to select the current conversation.
        final Conversation conv = mCallbacks.getCurrentConversation();
        if (conv != null) {
            if (mListView.getChoiceMode() != ListView.CHOICE_MODE_NONE
                    && mListView.getCheckedItemPosition() == -1) {
                setSelected(conv.position, true);
            }
        }
    }

    public void commitDestructiveActions(boolean animate) {
        if (mListView != null) {
            mListView.commitDestructiveActions(animate);

        }
    }

    @Override
    public void onListItemSwiped(Collection<Conversation> conversations) {
        mUpdater.showNextConversation(conversations);
    }

    private void checkSyncStatus() {
        if (mFolder != null && mFolder.isSyncInProgress()) {
            LogUtils.d(LOG_TAG, "CLF.checkSyncStatus still syncing");
            // Still syncing, ignore
        } else {
            // Finished syncing:
            LogUtils.d(LOG_TAG, "CLF.checkSyncStatus done syncing");
            mSwipeRefreshWidget.setRefreshing(false);
        }
    }

    /**
     * Displays the indefinite progress bar indicating a sync is in progress.  This
     * should only be called if user manually requested a sync, and not for background syncs.
     */
    protected void showSyncStatusBar() {
        mSwipeRefreshWidget.setRefreshing(true);
    }

    /**
     * Clears all items in the list.
     */
    public void clear() {
        mListView.setAdapter(null);
    }

    private final ConversationSetObserver mConversationSetObserver = new ConversationSetObserver() {
        @Override
        public void onSetPopulated(final ConversationSelectionSet set) {
            // Disable the swipe to refresh widget.
            mSwipeRefreshWidget.setEnabled(false);
        }

        @Override
        public void onSetEmpty() {
            //TS: wenggangjin 2015-03-17 EMAIL BUGFIX_-942413 MOD_S
            //TS: wenggangjin 2015-02-13 EMAIL BUGFIX_-930431 MOD_S
            // AM: Kexue.Geng 2015-03-18 EMAIL BUGFIX_952327 MOD_S
            // if(mActivity.getFolderController() == null || mActivity.getFolderController().getFolder() == null ){
            //     return;
            // }
            // AM: Kexue.Geng 2015-03-18 EMAIL BUGFIX_952327 MOD_E
            //TS: wenggangjin 2015-02-13 EMAIL BUGFIX_-930431 MOD_E
            //TS: wenggangjin 2015-03-17 EMAIL BUGFIX_-942413 MOD_E
            //TS: junwei-xu 2014-1-5 EMAIL BUGFIX_884395 MOD_S
            if (mActivity != null && mActivity.getFolderController() != null
                    && mActivity.getFolderController().getFolder() != null
                    && mActivity.getFolderController().getFolder().isDraft()) { // AM: Kexue.Geng 2015-03-18 EMAIL BUGFIX_952327
                mSwipeRefreshWidget.setEnabled(false);
            } else {
                mSwipeRefreshWidget.setEnabled(true);
            }
            //TS: junwei-xu 2014-1-5 EMAIL BUGFIX_884395 MOD_E
        }

        @Override
        public void onSetChanged(final ConversationSelectionSet set) {
            // Do nothing
        }
    };

    private void saveLastScrolledPosition() {
        //TS: lin-zhou 2015-11-12 EMAIL BUGFIX_1111531 MOD_S
        if (mListAdapter.getCursor() == null || mActivity == null || mFolder == null
                || mFolder.conversationListUri == null) {
            // If you save your scroll position in an empty list, you're gonna have a bad time
            return;
        }
        //TS: lin-zhou 2015-11-12 EMAIL BUGFIX_1111531 MOD_E

        final Parcelable savedState = mListView.onSaveInstanceState();

        mActivity.getListHandler().setConversationListScrollPosition(mFolder.conversationListUri.toString(),
                savedState);
    }

    private void restoreLastScrolledPosition() {
        // Scroll to our previous position, if necessary
        if (!mScrollPositionRestored && mFolder != null) {
            final String key = mFolder.conversationListUri.toString();
            final Parcelable savedState = mActivity.getListHandler().getConversationListScrollPosition(key);
            if (savedState != null) {
                mListView.onRestoreInstanceState(savedState);
            }
            mScrollPositionRestored = true;
        }
    }

    /* (non-Javadoc)
     * @see android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener#onRefresh()
     */
    @Override
    public void onRefresh() {
        //TS: tianjing.su 2016-03-14 EMAIL FEATURE_1804126 ADD_S
        try {
            if (mAccount != null && mAccount.getType().equals(getString(R.string.intent_exchange_package))) {
                int emailVersionCode = getActivity().getPackageManager()
                        .getPackageInfo(getString(R.string.email_package_name), 0).versionCode;
                int exchangeVersionCode = getActivity().getPackageManager()
                        .getPackageInfo(getString(R.string.intent_exchange_package), 1).versionCode;
                if (emailVersionCode != exchangeVersionCode) {
                    //[BUGFIX]-MOD by SCDTABLET.shujing.jin@tcl.com,08/05/2016,2635083
                    Utility.showToast(getActivity(), R.string.toast_warning_text);
                    //Toast.makeText(getActivity(), R.string.toast_warning_text, Toast.LENGTH_LONG).show();
                }
            }
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        //TS: tianjing.su 2016-03-14 EMAIL FEATURE_1804126 ADD_E
        Analytics.getInstance().sendEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, "swipe_refresh", null, 0);

        // This will call back to showSyncStatusBar():
        mActivity.getFolderController().requestFolderRefresh();

        // Clear list adapter state out of an abundance of caution.
        // There is a class of bugs where an animation that should have finished doesn't (maybe
        // it didn't start, or it didn't finish), and the list gets stuck pretty much forever.
        // Clearing the state here is in line with user expectation for 'refresh'.
        getAnimatedAdapter().clearAnimationState();
        // possibly act on the now-cleared state
        mActivity.onAnimationEnd(mListAdapter);
    }

    /**
     * Extracted function that handles Analytics state and logging updates for each new cursor
     * @param newCursor the new cursor pointer
     */
    private void updateAnalyticsData(ConversationCursor newCursor) {
        if (newCursor != null) {
            // Check if the initial data returned yet
            if (mInitialCursorLoading) {
                // This marks the very first time the cursor with the data the user sees returned.
                // We either have a cursor in LOADING state with cursor's count > 0, OR the cursor
                // completed loading.
                // Use this point to log the appropriate timing information that depends on when
                // the conversation list view finishes loading
                if (isCursorReadyToShow()) {
                    if (newCursor.getCount() == 0) {
                        Analytics.getInstance().sendEvent("empty_state", "post_label_change",
                                mFolder.getTypeDescription(), 0);
                    }
                    AnalyticsTimer.getInstance().logDuration(AnalyticsTimer.COLD_START_LAUNCHER,
                            true /* isDestructive */, "cold_start_to_list", "from_launcher", null);
                    // Don't need null checks because the activity, controller, and folder cannot
                    // be null in this case
                    // TS: Gantao 2016-01-19 EMAIL BUGFIX-1463224 MOD_S
                    //Do null checks
                    Folder folder = mActivity.getFolderController().getFolder();
                    if (folder != null && folder.isSearch()) {
                        AnalyticsTimer.getInstance().logDuration(AnalyticsTimer.SEARCH_TO_LIST,
                                true /* isDestructive */, "search_to_list", null, null);
                    }
                    // TS: Gantao 2016-01-19 EMAIL BUGFIX-1463224 MOD_E

                    mInitialCursorLoading = false;
                }
            } else {
                // Log the appropriate events that happen after the initial cursor is loaded
                if (newCursor.getCount() == 0 && mConversationCursorLastCount > 0) {
                    Analytics.getInstance().sendEvent("empty_state", "post_delete", mFolder.getTypeDescription(),
                            0);
                }
            }

            // We save the count here because for folders that are empty, multiple successful
            // cursor loads will occur with size of 0. Thus we don't want to emit any false
            // positive post_delete events.
            mConversationCursorLastCount = newCursor.getCount();
        } else {
            mConversationCursorLastCount = 0;
        }
    }

    /**
     * Helper function to determine if the current cursor is ready to populate the UI
     * Since we extracted the functionality into a static function in ConversationCursor,
     * this function remains for the sole purpose of readability.
     * @return
     */
    private boolean isCursorReadyToShow() {
        return ConversationCursor.isCursorReadyToShow(getConversationListCursor());
    }

    public ListView getListView() {
        return mListView;
    }

    public void setNextFocusLeftId(@IdRes int id) {
        mNextFocusLeftId = id;
        if (mListView != null) {
            mListView.setNextFocusLeftId(mNextFocusLeftId);
        }
    }

    //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_S
    class MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
                boolean airplaneModeOn = intent.getBooleanExtra("state", false);
                if (airplaneModeOn) {
                    mHandler.postDelayed(mHideLoadingRunnable, MINIMUM_LOADING_DURATION);
                    //TS: wenggangjin 2014-12-31 EMAIL BUGFIX_881447 MOD_S
                    mErrorListener.onError(mFolder, false);
                    //TS: wenggangjin 2014-12-31 EMAIL BUGFIX_881447 MOD_E
                } else {
                    mHandler.postDelayed(mLoadingViewRunnable, LOADING_DELAY_MS);
                }
            }
            //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD_S
            if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                ConnectivityManager connectivityManager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo info = connectivityManager.getActiveNetworkInfo();
                if (!(info != null && info.isConnected() && info.getState() == NetworkInfo.State.CONNECTED)) {
                    show = false;
                }
            }
            //TS: junwei-xu 2015-1-26 EMAIL BUGFIX_898211 ADD_E
        }
    }
    //TS: wenggangjin 2014-12-16 EMAIL BUGFIX_864636 MOD_E

    /// TCT: observer touch event, and hide keyboard in search mode when read search result.
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_DOWN
                || event.getAction() == MotionEvent.ACTION_MOVE) {
            // hide the soft keyboard while touch search mail list
            ActivityController activityController = (ActivityController) mActivity.getAccountController();
            ConversationListContext listContext = activityController.getCurrentListContext();
            if (listContext != null && listContext.isLocalSearch()) {
                //TS: rong-tang 2016-03-23 EMAIL BUGFIX-1815601 MOD_S
                hideSoftKeyboard((AbstractActivityController) activityController);
                //TS: rong-tang 2016-03-23 EMAIL BUGFIX-1815601 MOD_E
            }
        }
        // don't do anything, let the system process the event
        return false;
    }

    //TS: rong-tang 2016-03-23 EMAIL BUGFIX-1815601 MOD_S
    /// TCT: hide soft keyboard
    private void hideSoftKeyboard(AbstractActivityController controller) {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.hideSoftInputFromWindow(getListView().getWindowToken(), 0);
            //Note: after hide soft input, also need to clear focus which in search view.
            controller.mActionBarController.clearSearchFocus();
        }
    }
    //TS: rong-tang 2016-03-23 EMAIL BUGFIX-1815601 MOD_E

    /**
     * TCT: use to update footer view loading status.
     */
    public void updateFooterStatus(boolean isStarted) {
        mFooterView.updateLoadingStatus(isStarted);
    }

    /**
     * TCT: Update remote search result count.
     * @param count Count of results from remote search
     */
    private void updateRemoteSearchCount(AccountController controller, int count) {
        if (controller == null) {
            LogUtils.logFeature(LogTag.SEARCH_TAG, "updateRemoteSearchCount with controller is NULL");
            return;
        }
        AbstractActivityController aac = (AbstractActivityController) controller;
        aac.updateSearchResult(count);
    }

    /**
     * TCT: update local search result count.
     */
    private void updateLocalSearchCount(ConversationCursor cursor) {
        ActivityController activityController = (ActivityController) mActivity.getAccountController();
        ConversationListContext listContext = activityController.getCurrentListContext();
        if (cursor != null && listContext != null && listContext.isLocalSearchExecuted()
                && activityController instanceof AbstractActivityController) {
            LogUtils.v(LOG_TAG, "ConversationList changed, update local search result. count=" + cursor.getCount());
            AbstractActivityController aac = (AbstractActivityController) activityController;
            aac.updateSearchResult(cursor.getCount());
            //TS: junwei-xu 2015-12-25 EMAIL BUGFIX-1193902 DEL_S
            //Note: layout xml contains empty view, we don't need set empty view to list view.
            /*
            /// M: when search count is zero and not support remote search
            // set the mListView to empty view. @{
            if (cursor.getCount() == 0
                && (!mAccount.supportsCapability(AccountCapabilities.FOLDER_SERVER_SEARCH)
                /// M: OUTBOX and DRAFT folder is not show remote footer view, if
                // search count is 0, just show "No Messages".
                || mFolder.isType(UIProvider.FolderType.OUTBOX)
                || mFolder.isType(UIProvider.FolderType.DRAFT))) {
            mListView.setEmptyView(mEmptyView);
            } else {
            //TS: zheng.zou 2015-3-26 EMAIL BUGFIX_958910 ADD_S
            mListView.setEmptyView(null);
            //TS: zheng.zou 2015-3-26 EMAIL BUGFIX_958910 ADD_E
            }
            /// @}
            */
            //TS: junwei-xu 2015-12-25 EMAIL BUGFIX-1193902 DEL_E
        }
    }

    //TS: tao.gan 2015-10-12 EMAIL FEATURE-559891 ADD_S
    public ConversationListHeader getListHeader() {
        return mListHeader;
    }
    //TS: tao.gan 2015-10-12 EMAIL FEATURE-559891 ADD_E

    //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_S
    private boolean hasUpdateTimeView() {
        boolean hasUpdateTimeView = false;
        boolean lastUpdateTimeOn = PLFUtils.getBoolean(mActivity.getActivityContext(),
                "feature_email_lastUpdateTime_on");
        if (lastUpdateTimeOn && (mAccount != null && !mAccount.getAccountId().equalsIgnoreCase("Account Id"))) {
            hasUpdateTimeView = true;
        }
        return hasUpdateTimeView;
    }

    /**
     *update last update time.
     */
    private void updateHeaderView() {
        // update time stamp
        TextView timeStamp = (TextView) mConversationUpdateTimeView.findViewById(R.id.update_time);
        long time = (mViewContext.folder == null) ? 0 : mFolder.mSyncTime;
        String timeStampText;
        if (time == 0 && getActivity() != null) {
            timeStampText = getActivity().getResources().getString(R.string.conversation_update_unknown_time_stamp);
        } else {
            timeStampText = getElapseTime(time);
        }
        timeStamp.setText(" " + timeStampText);
    }

    /**
     *judge the folder whether to need update time view.
     */
    private boolean needListHeader() {
        if (mViewContext == null || mViewContext.folder == null && getActivity() == null) {
            return false;
        }
        //TS: zheng.zou 2016-1-14 EMAIL TASK_1431225 ADD_S
        if (!SortHelper.isTimeOrder(SortHelper.getCurrentSort())) {
            return false;
        }
        //TS: zheng.zou 2016-1-14 EMAIL TASK_1431225 ADD_E
        String protocol = com.tct.emailcommon.provider.Account.getProtocol(getActivity(),
                mViewContext.folder.mAccountKey);
        boolean isPopAccount = false;
        if (protocol != null && HostAuth.SCHEME_POP3.equalsIgnoreCase(protocol)) {
            isPopAccount = true;
        }
        if ((mViewContext != null) && (mViewContext.folder != null) && mViewContext.folder.isSyncable()
                && (mViewContext.folder.type != UIProvider.FolderType.OUTBOX)
                && (mViewContext.folder.type != UIProvider.FolderType.SEARCH)
                && !(isPopAccount && mViewContext.folder.type == UIProvider.FolderType.SENT)
                && !(isPopAccount && mViewContext.folder.type == UIProvider.FolderType.TRASH)) {
            return true;
        } else {
            return false;
        }
    }

    private String getElapseTime(long time) {
        long now = System.currentTimeMillis();
        long elapseTime = now - time;
        String displayTime;
        if (elapseTime < 0) {
            // abnormal time, this may occur when user change system time to a wrong time
            displayTime = (String) DateUtils.getRelativeTimeSpanString(mActivity.getActivityContext(), time);
        } else if (elapseTime < DateUtils.DAY_IN_MILLIS) {
            //within one day
            displayTime = (String) DateUtils.getRelativeTimeSpanString(mActivity.getActivityContext(), time);
            displayTime = mActivity.getActivityContext().getString(R.string.conversation_time_elapse_today) + ", "
                    + displayTime;
        } else {
            //beyond one day
            java.text.DateFormat timeFormat = DateFormat.getTimeFormat(mActivity.getActivityContext());
            Date date = new Date(time);
            String dateText = DateUtils.formatDateTime(mActivity.getActivityContext(), time,
                    DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH);
            displayTime = dateText + ", " + timeFormat.format(date);
        }

        return displayTime;
    }

    //TS: yanhua.chen 2015-10-28 EMAIL FR_1098700 ADD_E
}