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

Commit add4b5c4 authored by Fan Zhang's avatar Fan Zhang
Browse files

Query search result intent before launching to avoid crash

If intent cannot launch, log error.

Change-Id: Ib6f37da467749be1ef09e6665dcab122e71a52d3
Fix: 64065678
Test: robotests
parent 70f0013e
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -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);
    }
@@ -50,7 +57,14 @@ public class IntentSearchViewHolder extends SearchViewHolder {
                UserHandle userHandle = appResult.getAppUserHandle();
                fragment.getActivity().startActivityAsUser(intent, userHandle);
            } else {
                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);
                }
            }
        });
    }
+42 −9
Original line number Diff line number Diff line
@@ -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))