Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a84fe61b authored by Walter Jang's avatar Walter Jang
Browse files

Log when a search result is selected or search is abandoned (1/3)

* Populate a SearchState from the MultiSelectContactEntryListAdapter
  to with information about the number of results and partitions
  displayed to the user.  If a selection was made, record additional
  details.

Bug 26697731

Change-Id: I96de87ea1d297045421604ee0cd13c51c6c13dc4
parent f9ab10bf
Loading
Loading
Loading
Loading
+25 −7
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageButton;
import android.widget.Toast;

@@ -87,6 +86,8 @@ import com.android.contacts.list.OnContactsUnavailableActionListener;
import com.android.contacts.list.ProviderStatusWatcher;
import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
import com.android.contacts.common.list.ViewPagerTabs;
import com.android.contacts.common.logging.Logger;
import com.android.contacts.common.logging.ScreenEvent;
import com.android.contacts.preference.ContactsPreferenceActivity;
import com.android.contacts.common.util.AccountFilterUtil;
import com.android.contacts.common.util.ViewUtil;
@@ -564,13 +565,14 @@ public class PeopleActivity extends AppCompatContactsActivity implements
        switch (action) {
            case ActionBarAdapter.Listener.Action.START_SELECTION_MODE:
                mAllFragment.displayCheckBoxes(true);
                // Fall through:
                startSearchOrSelectionMode();
                break;
            case ActionBarAdapter.Listener.Action.START_SEARCH_MODE:
                // Tell the fragments that we're in the search mode or selection mode
                configureFragments(false /* from request */);
                updateFragmentsVisibility();
                invalidateOptionsMenu();
                showFabWithAnimation(/* showFabWithAnimation = */ false);
                if (!mIsRecreatedInstance) {
                    Logger.getInstance().logScreenView(
                            ScreenEvent.SEARCH, this, ScreenEvent.TAG_SEARCH);
                }
                startSearchOrSelectionMode();
                break;
            case ActionBarAdapter.Listener.Action.BEGIN_STOPPING_SEARCH_AND_SELECTION_MODE:
                showFabWithAnimation(/* showFabWithAnimation = */ true);
@@ -592,6 +594,13 @@ public class PeopleActivity extends AppCompatContactsActivity implements
        }
    }

    private void startSearchOrSelectionMode() {
        configureFragments(false /* from request */);
        updateFragmentsVisibility();
        invalidateOptionsMenu();
        showFabWithAnimation(/* showFabWithAnimation = */ false);
    }

    @Override
    public void onSelectedTabChanged() {
        updateFragmentsVisibility();
@@ -1315,6 +1324,7 @@ public class PeopleActivity extends AppCompatContactsActivity implements
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        ImplicitIntentsUtil.startActivityOutsideApp(this, intent);
    }

    private void joinSelectedContacts() {
        JoinContactsDialogFragment.start(this, mAllFragment.getSelectedContactIds());
    }
@@ -1396,6 +1406,14 @@ public class PeopleActivity extends AppCompatContactsActivity implements
            mAllFragment.displayCheckBoxes(false);
        } else if (mActionBarAdapter.isSearchMode()) {
            mActionBarAdapter.setSearchMode(false);

            if (mAllFragment.wasSearchResultClicked()) {
                mAllFragment.resetSearchResultClicked();
            } else {
                Logger.getInstance().logScreenView(
                        ScreenEvent.SEARCH_EXIT, this, ScreenEvent.TAG_SEARCH_EXIT);
                Logger.getInstance().logSearchEventImpl(mAllFragment.createSearchState());
            }
        } else {
            super.onBackPressed();
        }
+97 −0
Original line number Diff line number Diff line
@@ -19,14 +19,19 @@ package com.android.contacts.list;
import com.android.contacts.common.list.ContactListAdapter;
import com.android.contacts.common.list.ContactListItemView;
import com.android.contacts.common.list.DefaultContactListAdapter;
import com.android.contacts.common.logging.SearchState;
import com.android.contacts.list.MultiSelectEntryContactListAdapter.SelectedContactsListener;
import com.android.contacts.common.logging.Logger;

import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

/**
@@ -44,12 +49,31 @@ public class MultiSelectContactsListFragment extends DefaultContactBrowseListFra

    private static final String EXTRA_KEY_SELECTED_CONTACTS = "selected_contacts";

    private static final String KEY_SEARCH_RESULT_CLICKED = "search_result_clicked";

    private OnCheckBoxListActionListener mCheckBoxListListener;
    private boolean mSearchResultClicked;

    public void setCheckBoxListListener(OnCheckBoxListActionListener checkBoxListListener) {
        mCheckBoxListListener = checkBoxListListener;
    }

    /**
     * Whether a search result was clicked by the user. Tracked so that we can distinguish
     * between exiting the search mode after a result was clicked from existing w/o clicking
     * any search result.
     */
    public boolean wasSearchResultClicked() {
        return mSearchResultClicked;
    }

    /**
     * Resets whether a search result was clicked by the user to false.
     */
    public void resetSearchResultClicked() {
        mSearchResultClicked = false;
    }

    @Override
    public void onSelectedContactsChanged() {
        if (mCheckBoxListListener != null) {
@@ -77,6 +101,7 @@ public class MultiSelectContactsListFragment extends DefaultContactBrowseListFra
            if (mCheckBoxListListener != null) {
                mCheckBoxListListener.onSelectedContactIdsChanged();
            }
            mSearchResultClicked = savedInstanceState.getBoolean(KEY_SEARCH_RESULT_CLICKED);
        }
    }

@@ -100,6 +125,7 @@ public class MultiSelectContactsListFragment extends DefaultContactBrowseListFra
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putSerializable(EXTRA_KEY_SELECTED_CONTACTS, getSelectedContactIds());
        outState.putBoolean(KEY_SEARCH_RESULT_CLICKED, mSearchResultClicked);
    }

    public void displayCheckBoxes(boolean displayCheckBoxes) {
@@ -157,6 +183,10 @@ public class MultiSelectContactsListFragment extends DefaultContactBrowseListFra
                getAdapter().toggleSelectionOfContactId(Long.valueOf(contactId));
            }
        } else {
            mSearchResultClicked = true;
            Logger.getInstance().logSearchEventImpl(
                    createSearchStateForSearchResultClick(position));

            super.onItemClick(position, id);
        }
        if (mCheckBoxListListener != null && getAdapter().getSelectedContactIds().size() == 0) {
@@ -164,6 +194,73 @@ public class MultiSelectContactsListFragment extends DefaultContactBrowseListFra
        }
    }

    /**
     * Returns the state of the search results currently presented to the user.
     */
    public SearchState createSearchState() {
        return createSearchState(/* selectedPosition */ -1);
    }

    /**
     * Returns the state of the search results presented to the user
     * at the time the result in the given position was clicked.
     */
    public SearchState createSearchStateForSearchResultClick(int selectedPosition) {
        return createSearchState(selectedPosition);
    }

    private SearchState createSearchState(int selectedPosition) {
        final MultiSelectEntryContactListAdapter adapter = getAdapter();
        if (adapter == null) {
            return null;
        }
        final SearchState searchState = new SearchState();
        searchState.queryLength = adapter.getQueryString() == null
                ? 0 : adapter.getQueryString().length();
        searchState.numPartitions = adapter.getPartitionCount();

        // Set the number of results displayed to the user.  Note that the adapter.getCount(),
        // value does not always match the number of results actually displayed to the user,
        // which is why we calculate it manually.
        final List<Integer> numResultsInEachPartition = new ArrayList<>();
        for (int i = 0; i < adapter.getPartitionCount(); i++) {
            final Cursor cursor = adapter.getCursor(i);
            if (cursor == null || cursor.isClosed()) {
                // Something went wrong, abort.
                numResultsInEachPartition.clear();
                break;
            }
            numResultsInEachPartition.add(cursor.getCount());
        }
        if (!numResultsInEachPartition.isEmpty()) {
            int numResults = 0;
            for (int i = 0; i < numResultsInEachPartition.size(); i++) {
                numResults += numResultsInEachPartition.get(i);
            }
            searchState.numResults = numResults;
        }

        // If a selection was made, set additional search state
        if (selectedPosition >= 0) {
            searchState.selectedPartition = adapter.getPartitionForPosition(selectedPosition);
            searchState.selectedIndexInPartition = adapter.getOffsetInPartition(selectedPosition);
            final Cursor cursor = adapter.getCursor(searchState.selectedPartition);
            searchState.numResultsInSelectedPartition =
                    cursor == null || cursor.isClosed() ? -1 : cursor.getCount();

            // Calculate the index across all partitions
            if (!numResultsInEachPartition.isEmpty()) {
                int selectedIndex = 0;
                for (int i = 0; i < searchState.selectedPartition; i++) {
                    selectedIndex += numResultsInEachPartition.get(i);
                }
                selectedIndex += searchState.selectedIndexInPartition;
                searchState.selectedIndex = selectedIndex;
            }
        }
        return searchState;
    }

    @Override
    protected ContactListAdapter createListAdapter() {
        DefaultContactListAdapter adapter = new MultiSelectEntryContactListAdapter(getContext());