Add logging to search fragment.

- User leaves screen without any query
- Number of results clicked before leaving screen
- Event of each result click

Bug: 34204146
Test: RunSettingsRoboTests

Change-Id: I357fbb4cdfd4d02370791b4a2ddeb2127fdddf97
This commit is contained in:
Fan Zhang
2017-01-10 09:52:01 -08:00
parent 8116060570
commit 39f4f6ee60
7 changed files with 62 additions and 21 deletions

View File

@@ -17,14 +17,11 @@
package com.android.settings.search2; package com.android.settings.search2;
import android.app.Fragment; import android.content.Context;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewParent;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.Switch; import android.widget.Switch;
import android.widget.TextView; import android.widget.TextView;
import android.content.Context;
import com.android.internal.widget.PreferenceImageView; import com.android.internal.widget.PreferenceImageView;
import com.android.settings.R; import com.android.settings.R;
@@ -52,7 +49,7 @@ public class InlineSwitchViewHolder extends SearchViewHolder {
} }
@Override @Override
public void onBind(Fragment fragment, SearchResult result) { public void onBind(SearchFragment fragment, SearchResult result) {
if (mContext == null) { if (mContext == null) {
return; return;
} }
@@ -62,6 +59,7 @@ public class InlineSwitchViewHolder extends SearchViewHolder {
switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
fragment.onSearchResultClicked();
payload.setSwitchValue(mContext, isChecked); payload.setSwitchValue(mContext, isChecked);
} }
}); });

View File

@@ -15,7 +15,6 @@
*/ */
package com.android.settings.search2; package com.android.settings.search2;
import android.app.Fragment;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@@ -40,7 +39,7 @@ public class IntentSearchViewHolder extends SearchViewHolder {
} }
@Override @Override
public void onBind(final Fragment fragment, final SearchResult result) { public void onBind(final SearchFragment fragment, final SearchResult result) {
titleView.setText(result.title); titleView.setText(result.title);
summaryView.setText(result.summary); summaryView.setText(result.summary);
iconView.setImageDrawable(result.icon); iconView.setImageDrawable(result.icon);
@@ -50,6 +49,7 @@ public class IntentSearchViewHolder extends SearchViewHolder {
itemView.setOnClickListener(new View.OnClickListener() { itemView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
fragment.onSearchResultClicked();
fragment.startActivity(((IntentPayload) result.payload).intent); fragment.startActivity(((IntentPayload) result.payload).intent);
} }
}); });

View File

@@ -35,23 +35,33 @@ import android.widget.SearchView;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment; import com.android.settings.core.InstrumentedFragment;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import java.util.List; import java.util.List;
public class SearchFragment extends InstrumentedFragment implements public class SearchFragment extends InstrumentedFragment implements
SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<List<SearchResult>> { SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<List<SearchResult>> {
private static final String TAG = "SearchFragment";
// State values // State values
static final String STATE_QUERY = "query"; private static final String STATE_QUERY = "state_query";
private static final String STATE_NEVER_ENTERED_QUERY = "state_never_entered_query";
private static final String STATE_RESULT_CLICK_COUNT = "state_result_click_count";
// Loader IDs // Loader IDs
private static final int LOADER_ID_DATABASE = 0; private static final int LOADER_ID_DATABASE = 0;
private static final int LOADER_ID_INSTALLED_APPS = 1; private static final int LOADER_ID_INSTALLED_APPS = 1;
@VisibleForTesting // Logging
String mQuery; @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
static final String RESULT_CLICK_COUNT = "settings_search_result_click_count";
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
String mQuery;
private boolean mNeverEnteredQuery = true;
private int mResultClickCount;
private MetricsFeatureProvider mMetricsFeatureProvider;
private SearchFeatureProvider mSearchFeatureProvider; private SearchFeatureProvider mSearchFeatureProvider;
private SearchResultsAdapter mSearchAdapter; private SearchResultsAdapter mSearchAdapter;
@@ -65,8 +75,8 @@ public class SearchFragment extends InstrumentedFragment implements
@Override @Override
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
mSearchFeatureProvider = FeatureFactory.getFactory(context) mSearchFeatureProvider = FeatureFactory.getFactory(context).getSearchFeatureProvider();
.getSearchFeatureProvider(); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
} }
@Override @Override
@@ -76,6 +86,8 @@ public class SearchFragment extends InstrumentedFragment implements
mSearchAdapter = new SearchResultsAdapter(this); mSearchAdapter = new SearchResultsAdapter(this);
if (savedInstanceState != null) { if (savedInstanceState != null) {
mQuery = savedInstanceState.getString(STATE_QUERY); mQuery = savedInstanceState.getString(STATE_QUERY);
mNeverEnteredQuery = savedInstanceState.getBoolean(STATE_NEVER_ENTERED_QUERY);
mResultClickCount = savedInstanceState.getInt(STATE_RESULT_CLICK_COUNT);
final LoaderManager loaderManager = getLoaderManager(); final LoaderManager loaderManager = getLoaderManager();
loaderManager.initLoader(LOADER_ID_DATABASE, null, this); loaderManager.initLoader(LOADER_ID_DATABASE, null, this);
loaderManager.initLoader(LOADER_ID_INSTALLED_APPS, null, this); loaderManager.initLoader(LOADER_ID_INSTALLED_APPS, null, this);
@@ -96,10 +108,25 @@ public class SearchFragment extends InstrumentedFragment implements
return view; return view;
} }
@Override
public void onStop() {
super.onStop();
final Activity activity = getActivity();
if (activity != null && activity.isFinishing()) {
mMetricsFeatureProvider.histogram(activity, RESULT_CLICK_COUNT, mResultClickCount);
if (mNeverEnteredQuery) {
mMetricsFeatureProvider.action(activity,
MetricsProto.MetricsEvent.ACTION_LEAVE_SEARCH_RESULT_WITHOUT_QUERY);
}
}
}
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putString(STATE_QUERY, mQuery); outState.putString(STATE_QUERY, mQuery);
outState.putBoolean(STATE_NEVER_ENTERED_QUERY, mNeverEnteredQuery);
outState.putInt(STATE_RESULT_CLICK_COUNT, mResultClickCount);
} }
@Override @Override
@@ -107,6 +134,8 @@ public class SearchFragment extends InstrumentedFragment implements
if (TextUtils.equals(query, mQuery)) { if (TextUtils.equals(query, mQuery)) {
return true; return true;
} }
mResultClickCount = 0;
mNeverEnteredQuery = false;
mQuery = query; mQuery = query;
mSearchAdapter.clearResults(); mSearchAdapter.clearResults();
@@ -147,6 +176,10 @@ public class SearchFragment extends InstrumentedFragment implements
public void onLoaderReset(Loader<List<SearchResult>> loader) { public void onLoaderReset(Loader<List<SearchResult>> loader) {
} }
public void onSearchResultClicked() {
mResultClickCount++;
}
private void restartLoaders() { private void restartLoaders() {
final LoaderManager loaderManager = getLoaderManager(); final LoaderManager loaderManager = getLoaderManager();
loaderManager.restartLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */); loaderManager.restartLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */);

View File

@@ -15,7 +15,6 @@
*/ */
package com.android.settings.search2; package com.android.settings.search2;
import android.app.Fragment;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
@@ -30,5 +29,5 @@ public abstract class SearchViewHolder extends RecyclerView.ViewHolder {
super(view); super(view);
} }
public abstract void onBind(Fragment fragment, SearchResult result); public abstract void onBind(SearchFragment fragment, SearchResult result);
} }

View File

@@ -17,7 +17,6 @@
package com.android.settings.search; package com.android.settings.search;
import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -28,7 +27,7 @@ import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.search2.InlineSwitchPayload; import com.android.settings.search2.InlineSwitchPayload;
import com.android.settings.search2.InlineSwitchViewHolder; import com.android.settings.search2.InlineSwitchViewHolder;
import com.android.settings.search2.IntentPayload; import com.android.settings.search2.SearchFragment;
import com.android.settings.search2.SearchResult; import com.android.settings.search2.SearchResult;
import org.junit.Before; import org.junit.Before;
@@ -53,7 +52,7 @@ public class InlineSwitchViewHolderTest {
private static final String SUMMARY = "summary"; private static final String SUMMARY = "summary";
@Mock @Mock
private Fragment mFragment; private SearchFragment mFragment;
@Mock @Mock
private InlineSwitchPayload mPayload; private InlineSwitchPayload mPayload;
@@ -97,7 +96,7 @@ public class InlineSwitchViewHolderTest {
.addSummary(SUMMARY) .addSummary(SUMMARY)
.addRank(1) .addRank(1)
.addPayload(new InlineSwitchPayload("", 0, null)) .addPayload(new InlineSwitchPayload("", 0, null))
.addBreadcrumbs(new ArrayList<String>()) .addBreadcrumbs(new ArrayList<>())
.addIcon(mIcon) .addIcon(mIcon)
.addPayload(mPayload); .addPayload(mPayload);

View File

@@ -17,7 +17,6 @@
package com.android.settings.search; package com.android.settings.search;
import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -29,6 +28,7 @@ import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.search2.IntentPayload; import com.android.settings.search2.IntentPayload;
import com.android.settings.search2.IntentSearchViewHolder; import com.android.settings.search2.IntentSearchViewHolder;
import com.android.settings.search2.SearchFragment;
import com.android.settings.search2.SearchResult; import com.android.settings.search2.SearchResult;
import com.android.settings.search2.SearchResult.Builder; import com.android.settings.search2.SearchResult.Builder;
@@ -54,7 +54,7 @@ public class IntentSearchViewHolderTest {
private static final String SUMMARY = "summary"; private static final String SUMMARY = "summary";
@Mock @Mock
private Fragment mFragment; private SearchFragment mFragment;
private IntentSearchViewHolder mHolder; private IntentSearchViewHolder mHolder;
private Drawable mIcon; private Drawable mIcon;
@@ -84,6 +84,8 @@ public class IntentSearchViewHolderTest {
assertThat(mHolder.titleView.getText()).isEqualTo(TITLE); assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY); assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
assertThat(mHolder.iconView.getDrawable()).isEqualTo(mIcon); assertThat(mHolder.iconView.getDrawable()).isEqualTo(mIcon);
verify(mFragment).onSearchResultClicked();
verify(mFragment).startActivity(any(Intent.class)); verify(mFragment).startActivity(any(Intent.class));
} }
@@ -93,7 +95,7 @@ public class IntentSearchViewHolderTest {
.addSummary(SUMMARY) .addSummary(SUMMARY)
.addRank(1) .addRank(1)
.addPayload(new IntentPayload(null)) .addPayload(new IntentPayload(null))
.addBreadcrumbs(new ArrayList<String>()) .addBreadcrumbs(new ArrayList<>())
.addIcon(mIcon); .addIcon(mIcon);
return builder.build(); return builder.build();

View File

@@ -19,6 +19,7 @@ package com.android.settings.search2;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
@@ -36,6 +37,8 @@ import org.robolectric.util.ActivityController;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -97,7 +100,14 @@ public class SearchFragmentTest {
.findFragmentById(R.id.main_content); .findFragmentById(R.id.main_content);
fragment.onQueryTextChange(testQuery); fragment.onQueryTextChange(testQuery);
activityController.get().onBackPressed();
activityController.pause().stop().destroy();
verify(mFeatureFactory.metricsFeatureProvider, never()).action(
any(Context.class),
eq(MetricsProto.MetricsEvent.ACTION_LEAVE_SEARCH_RESULT_WITHOUT_QUERY));
verify(mFeatureFactory.metricsFeatureProvider).histogram(
any(Context.class), eq(SearchFragment.RESULT_CLICK_COUNT), eq(0));
verify(mFeatureFactory.searchFeatureProvider) verify(mFeatureFactory.searchFeatureProvider)
.getDatabaseSearchLoader(any(Context.class), anyString()); .getDatabaseSearchLoader(any(Context.class), anyString());
verify(mFeatureFactory.searchFeatureProvider) verify(mFeatureFactory.searchFeatureProvider)