Query search result intent before launching to avoid crash

If intent cannot launch, log error.

Change-Id: Ib6f37da467749be1ef09e6665dcab122e71a52d3
Fix: 64065678
Test: robotests
This commit is contained in:
Fan Zhang
2017-07-27 17:50:41 -07:00
parent 70f0013e43
commit add4b5c413
2 changed files with 58 additions and 11 deletions

View File

@@ -17,17 +17,24 @@
package com.android.settings.search; package com.android.settings.search;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.Log;
import android.view.View; import android.view.View;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import java.util.List;
/** /**
* ViewHolder for intent based search results. * ViewHolder for intent based search results.
* The DatabaseResultLoader is the primary use case for this ViewHolder. * The DatabaseResultLoader is the primary use case for this ViewHolder.
*/ */
public class IntentSearchViewHolder extends SearchViewHolder { public class IntentSearchViewHolder extends SearchViewHolder {
private static final String TAG = "IntentSearchViewHolder";
public IntentSearchViewHolder(View view) { public IntentSearchViewHolder(View view) {
super(view); super(view);
} }
@@ -50,7 +57,14 @@ public class IntentSearchViewHolder extends SearchViewHolder {
UserHandle userHandle = appResult.getAppUserHandle(); UserHandle userHandle = appResult.getAppUserHandle();
fragment.getActivity().startActivityAsUser(intent, userHandle); fragment.getActivity().startActivityAsUser(intent, userHandle);
} else { } else {
final PackageManager pm = fragment.getActivity().getPackageManager();
final List<ResolveInfo> info = pm.queryIntentActivities(intent, 0 /* flags */);
if (info != null && !info.isEmpty()) {
fragment.startActivity(intent); fragment.startActivity(intent);
} else {
Log.e(TAG, "Cannot launch search result, title: "
+ result.title + ", " + intent);
}
} }
}); });
} }

View File

@@ -18,10 +18,10 @@
package com.android.settings.search; package com.android.settings.search;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -31,6 +31,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.UserHandle; import android.os.UserHandle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -52,6 +53,7 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -82,7 +84,7 @@ public class IntentSearchViewHolderTest {
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
final Context context = RuntimeEnvironment.application; final Context context = RuntimeEnvironment.application;
View view = LayoutInflater.from(context).inflate(R.layout.search_intent_item, null); final View view = LayoutInflater.from(context).inflate(R.layout.search_intent_item, null);
mHolder = new IntentSearchViewHolder(view); mHolder = new IntentSearchViewHolder(view);
mIcon = context.getDrawable(R.drawable.ic_search_history); mIcon = context.getDrawable(R.drawable.ic_search_history);
@@ -100,7 +102,7 @@ public class IntentSearchViewHolderTest {
@Test @Test
public void testBindViewElements_allUpdated() { public void testBindViewElements_allUpdated() {
SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon); final SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon);
mHolder.onBind(mFragment, result); mHolder.onBind(mFragment, result);
mHolder.itemView.performClick(); mHolder.itemView.performClick();
@@ -111,7 +113,6 @@ public class IntentSearchViewHolderTest {
assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE); assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE);
verify(mFragment).onSearchResultClicked(eq(mHolder), any(SearchResult.class)); verify(mFragment).onSearchResultClicked(eq(mHolder), any(SearchResult.class));
verify(mFragment).startActivity(any(Intent.class));
} }
@Test @Test
@@ -158,8 +159,8 @@ public class IntentSearchViewHolderTest {
@Test @Test
public void testBindElements_placeholderSummary_visibilityIsGone() { public void testBindElements_placeholderSummary_visibilityIsGone() {
String nonBreakingSpace = mContext.getString(R.string.summary_placeholder); final String nonBreakingSpace = mContext.getString(R.string.summary_placeholder);
SearchResult result = new Builder() final SearchResult result = new Builder()
.setTitle(TITLE) .setTitle(TITLE)
.setSummary(nonBreakingSpace) .setSummary(nonBreakingSpace)
.setPayload(new ResultPayload(null)) .setPayload(new ResultPayload(null))
@@ -173,8 +174,8 @@ public class IntentSearchViewHolderTest {
@Test @Test
public void testBindElements_dynamicSummary_visibilityIsGone() { public void testBindElements_dynamicSummary_visibilityIsGone() {
String dynamicSummary = "%s"; final String dynamicSummary = "%s";
SearchResult result = new Builder() final SearchResult result = new Builder()
.setTitle(TITLE) .setTitle(TITLE)
.setSummary(dynamicSummary) .setSummary(dynamicSummary)
.setPayload(new ResultPayload(null)) .setPayload(new ResultPayload(null))
@@ -191,7 +192,7 @@ public class IntentSearchViewHolderTest {
when(mPackageManager.getUserBadgedLabel(any(CharSequence.class), when(mPackageManager.getUserBadgedLabel(any(CharSequence.class),
eq(new UserHandle(USER_ID)))).thenReturn(BADGED_LABEL); eq(new UserHandle(USER_ID)))).thenReturn(BADGED_LABEL);
SearchResult result = getAppSearchResult( final SearchResult result = getAppSearchResult(
TITLE, SUMMARY, mIcon, getApplicationInfo(USER_ID, TITLE, mIcon)); TITLE, SUMMARY, mIcon, getApplicationInfo(USER_ID, TITLE, mIcon));
mHolder.onBind(mFragment, result); mHolder.onBind(mFragment, result);
mHolder.itemView.performClick(); mHolder.itemView.performClick();
@@ -207,6 +208,38 @@ public class IntentSearchViewHolderTest {
any(Intent.class), eq(new UserHandle(USER_ID))); any(Intent.class), eq(new UserHandle(USER_ID)));
} }
@Test
public void testBindViewElements_validSubSettingIntent_shouldLaunch() {
final SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon);
when(mPackageManager.queryIntentActivities(result.payload.getIntent(), 0 /* flags */))
.thenReturn(Arrays.asList(new ResolveInfo()));
mHolder.onBind(mFragment, result);
mHolder.itemView.performClick();
assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.VISIBLE);
verify(mFragment).onSearchResultClicked(eq(mHolder), any(SearchResult.class));
verify(mFragment).startActivity(result.payload.getIntent());
}
@Test
public void testBindViewElements_invalidSubSettingIntent_shouldNotLaunchAnything() {
final SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon);
when(mPackageManager.queryIntentActivities(result.payload.getIntent(), 0 /* flags */))
.thenReturn(null);
mHolder.onBind(mFragment, result);
mHolder.itemView.performClick();
assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.VISIBLE);
verify(mFragment).onSearchResultClicked(eq(mHolder), any(SearchResult.class));
verify(mFragment, never()).startActivity(any(Intent.class));
}
private SearchResult getSearchResult(String title, String summary, Drawable icon) { private SearchResult getSearchResult(String title, String summary, Drawable icon) {
Builder builder = new Builder(); Builder builder = new Builder();
builder.setStableId(Objects.hash(title, summary, icon)) builder.setStableId(Objects.hash(title, summary, icon))