From a75a724bdd5c7c6e2b7841fb634729283b3c42f9 Mon Sep 17 00:00:00 2001 From: Raff Tsai Date: Thu, 15 Nov 2018 13:35:36 +0800 Subject: [PATCH] Fix Settings crash when clicking search bar - When user disable settings suggestion in App Settings, click search button without leaving settings app. The search button is still existed. - Doesn't allow user to disable app in App Settings - Add check before start search intent Change-Id: Ifbc4615914678d8df734e14d63bb626403313d1e Fixes: 118805907 Test: manual --- .../ApplicationFeatureProviderImpl.java | 4 +++ .../search/SearchFeatureProvider.java | 6 ++++ .../actionbar/SearchMenuController.java | 7 ++++ .../ApplicationFeatureProviderImplTest.java | 6 +++- .../search/SearchFeatureProviderImplTest.java | 35 ++++++++++++++++--- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index d29fc950b1d..c246c58eadc 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -32,6 +32,7 @@ import android.text.TextUtils; import android.util.ArraySet; import com.android.internal.telephony.SmsApplication; +import com.android.settings.R; import java.util.ArrayList; import java.util.List; @@ -138,6 +139,9 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide if (defaultSms != null) { keepEnabledPackages.add(defaultSms.getPackageName()); } + // Keep Settings intelligence enabled, otherwise search feature will be disabled. + keepEnabledPackages.add( + mContext.getString(R.string.config_settingsintelligence_package_name)); return keepEnabledPackages; } diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java index 464b8f5ef2f..3c1c62b43c7 100644 --- a/src/com/android/settings/search/SearchFeatureProvider.java +++ b/src/com/android/settings/search/SearchFeatureProvider.java @@ -23,6 +23,7 @@ import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.provider.Settings; import android.view.View; import android.view.ViewGroup; @@ -88,6 +89,11 @@ public interface SearchFeatureProvider { intent.setPackage(getSettingsIntelligencePkgName(activity)); final Context context = activity.getApplicationContext(); + if (activity.getPackageManager().queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { + return; + } + FeatureFactory.getFactory(context).getSlicesFeatureProvider() .indexSliceDataAsync(activity.getApplicationContext()); FeatureFactory.getFactory(context).getMetricsFeatureProvider() diff --git a/src/com/android/settings/search/actionbar/SearchMenuController.java b/src/com/android/settings/search/actionbar/SearchMenuController.java index 22adbeba775..643f0c3493a 100644 --- a/src/com/android/settings/search/actionbar/SearchMenuController.java +++ b/src/com/android/settings/search/actionbar/SearchMenuController.java @@ -19,6 +19,7 @@ package com.android.settings.search.actionbar; import android.annotation.NonNull; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; @@ -80,6 +81,12 @@ public class SearchMenuController implements LifecycleObserver, OnCreateOptionsM searchItem.setOnMenuItemClickListener(target -> { final Intent intent = SearchFeatureProvider.SEARCH_UI_INTENT; intent.setPackage(SettingsIntelligencePkgName); + + if (context.getPackageManager().queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { + return true; + } + FeatureFactory.getFactory(context).getMetricsFeatureProvider() .action(context, MetricsProto.MetricsEvent.ACTION_SEARCH_RESULTS); mHost.startActivityForResult(intent, 0 /* requestCode */); diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java index ba07dc5caed..128f34547a4 100644 --- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java @@ -34,6 +34,7 @@ import android.os.Build; import android.os.UserHandle; import android.os.UserManager; +import com.android.settings.R; import com.android.settings.testutils.ApplicationTestUtils; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager; @@ -258,13 +259,16 @@ public final class ApplicationFeatureProviderImplTest { public void getKeepEnabledPackages_shouldContainDefaultPhoneAndSms() { final String testDialer = "com.android.test.defaultdialer"; final String testSms = "com.android.test.defaultsms"; + final String settingsIntelligence = RuntimeEnvironment.application.getString( + R.string.config_settingsintelligence_package_name); ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); ReflectionHelpers.setField(mProvider, "mContext", RuntimeEnvironment.application); final Set keepEnabledPackages = mProvider.getKeepEnabledPackages(); - final List expectedPackages = Arrays.asList(testDialer, testSms); + final List expectedPackages = Arrays.asList(testDialer, testSms, + settingsIntelligence); assertThat(keepEnabledPackages).containsExactlyElementsIn(expectedPackages); } diff --git a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java index bcb9372308b..b0e40255622 100644 --- a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java @@ -19,14 +19,15 @@ package com.android.settings.search; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; - import android.app.Activity; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ResolveInfo; import android.provider.Settings; import android.widget.Toolbar; +import com.android.settings.R; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowUtils; @@ -37,25 +38,34 @@ import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.Shadows; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowPackageManager; @RunWith(SettingsRobolectricTestRunner.class) public class SearchFeatureProviderImplTest { private SearchFeatureProviderImpl mProvider; private Activity mActivity; + private ShadowPackageManager mPackageManager; @Before public void setUp() { FakeFeatureFactory.setupForTest(); mActivity = Robolectric.setupActivity(Activity.class); - mProvider = spy(new SearchFeatureProviderImpl()); + mProvider = new SearchFeatureProviderImpl(); + mPackageManager = Shadows.shadowOf(mActivity.getPackageManager()); } @Test @Config(shadows = ShadowUtils.class) - public void initSearchToolbar_shouldInitWithOnClickListener() { - mProvider.initSearchToolbar(mActivity, null); + public void initSearchToolbar_hasResolvedInfo_shouldStartCorrectIntent() { + final Intent searchIntent = new Intent(SearchFeatureProvider.SEARCH_UI_INTENT) + .setPackage(mActivity.getString(R.string.config_settingsintelligence_package_name)); + final ResolveInfo info = new ResolveInfo(); + info.activityInfo = new ActivityInfo(); + mPackageManager.addResolveInfoForIntent(searchIntent, info); + // Should not crash. + mProvider.initSearchToolbar(mActivity, null); final Toolbar toolbar = new Toolbar(mActivity); // This ensures navigationView is created. @@ -70,6 +80,21 @@ public class SearchFeatureProviderImplTest { .isEqualTo(Settings.ACTION_APP_SEARCH_SETTINGS); } + @Test + @Config(shadows = ShadowUtils.class) + public void initSearchToolbar_NotHaveResolvedInfo_shouldNotStartActivity() { + final Toolbar toolbar = new Toolbar(mActivity); + // This ensures navigationView is created. + toolbar.setNavigationContentDescription("test"); + mProvider.initSearchToolbar(mActivity, toolbar); + + toolbar.performClick(); + + final Intent launchIntent = Shadows.shadowOf(mActivity).getNextStartedActivity(); + + assertThat(launchIntent).isNull(); + } + @Test(expected = IllegalArgumentException.class) public void verifyLaunchSearchResultPageCaller_nullCaller_shouldCrash() { mProvider.verifyLaunchSearchResultPageCaller(mActivity, null /* caller */);