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:
@@ -17,17 +17,24 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ViewHolder for intent based search results.
|
||||
* The DatabaseResultLoader is the primary use case for this ViewHolder.
|
||||
*/
|
||||
public class IntentSearchViewHolder extends SearchViewHolder {
|
||||
|
||||
private static final String TAG = "IntentSearchViewHolder";
|
||||
|
||||
public IntentSearchViewHolder(View view) {
|
||||
super(view);
|
||||
}
|
||||
@@ -42,7 +49,7 @@ public class IntentSearchViewHolder extends SearchViewHolder {
|
||||
super.onBind(fragment, result);
|
||||
|
||||
itemView.setOnClickListener(v -> {
|
||||
fragment.onSearchResultClicked(this, result);
|
||||
fragment.onSearchResultClicked(this, result);
|
||||
final Intent intent = result.payload.getIntent();
|
||||
// Use app user id to support work profile use case.
|
||||
if (result instanceof AppSearchResult) {
|
||||
@@ -50,7 +57,14 @@ public class IntentSearchViewHolder extends SearchViewHolder {
|
||||
UserHandle userHandle = appResult.getAppUserHandle();
|
||||
fragment.getActivity().startActivityAsUser(intent, userHandle);
|
||||
} else {
|
||||
fragment.startActivity(intent);
|
||||
final PackageManager pm = fragment.getActivity().getPackageManager();
|
||||
final List<ResolveInfo> info = pm.queryIntentActivities(intent, 0 /* flags */);
|
||||
if (info != null && !info.isEmpty()) {
|
||||
fragment.startActivity(intent);
|
||||
} else {
|
||||
Log.e(TAG, "Cannot launch search result, title: "
|
||||
+ result.title + ", " + intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -18,10 +18,10 @@
|
||||
package com.android.settings.search;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -31,6 +31,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -52,6 +53,7 @@ import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -82,7 +84,7 @@ public class IntentSearchViewHolderTest {
|
||||
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
|
||||
|
||||
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);
|
||||
|
||||
mIcon = context.getDrawable(R.drawable.ic_search_history);
|
||||
@@ -100,7 +102,7 @@ public class IntentSearchViewHolderTest {
|
||||
|
||||
@Test
|
||||
public void testBindViewElements_allUpdated() {
|
||||
SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon);
|
||||
final SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon);
|
||||
mHolder.onBind(mFragment, result);
|
||||
mHolder.itemView.performClick();
|
||||
|
||||
@@ -111,7 +113,6 @@ public class IntentSearchViewHolderTest {
|
||||
assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE);
|
||||
|
||||
verify(mFragment).onSearchResultClicked(eq(mHolder), any(SearchResult.class));
|
||||
verify(mFragment).startActivity(any(Intent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -158,8 +159,8 @@ public class IntentSearchViewHolderTest {
|
||||
|
||||
@Test
|
||||
public void testBindElements_placeholderSummary_visibilityIsGone() {
|
||||
String nonBreakingSpace = mContext.getString(R.string.summary_placeholder);
|
||||
SearchResult result = new Builder()
|
||||
final String nonBreakingSpace = mContext.getString(R.string.summary_placeholder);
|
||||
final SearchResult result = new Builder()
|
||||
.setTitle(TITLE)
|
||||
.setSummary(nonBreakingSpace)
|
||||
.setPayload(new ResultPayload(null))
|
||||
@@ -173,8 +174,8 @@ public class IntentSearchViewHolderTest {
|
||||
|
||||
@Test
|
||||
public void testBindElements_dynamicSummary_visibilityIsGone() {
|
||||
String dynamicSummary = "%s";
|
||||
SearchResult result = new Builder()
|
||||
final String dynamicSummary = "%s";
|
||||
final SearchResult result = new Builder()
|
||||
.setTitle(TITLE)
|
||||
.setSummary(dynamicSummary)
|
||||
.setPayload(new ResultPayload(null))
|
||||
@@ -191,7 +192,7 @@ public class IntentSearchViewHolderTest {
|
||||
when(mPackageManager.getUserBadgedLabel(any(CharSequence.class),
|
||||
eq(new UserHandle(USER_ID)))).thenReturn(BADGED_LABEL);
|
||||
|
||||
SearchResult result = getAppSearchResult(
|
||||
final SearchResult result = getAppSearchResult(
|
||||
TITLE, SUMMARY, mIcon, getApplicationInfo(USER_ID, TITLE, mIcon));
|
||||
mHolder.onBind(mFragment, result);
|
||||
mHolder.itemView.performClick();
|
||||
@@ -207,6 +208,38 @@ public class IntentSearchViewHolderTest {
|
||||
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) {
|
||||
Builder builder = new Builder();
|
||||
builder.setStableId(Objects.hash(title, summary, icon))
|
||||
|
Reference in New Issue
Block a user