Provide installed a11y services/activities from dynamicRawData for search

Bug: 354076686
Flag: com.android.settings.accessibility.fix_a11y_settings_search
Test: Search Project Relate and verify the item shows up in the search
result
Test: Search Talkback with keywords, verify the Talkback shows up in the
search result
Test: atest AccessibilitySettingsTest

Change-Id: I258ecb0928308b7cde30c12104408e11cc25ecd5
This commit is contained in:
Chun-Ku Lin
2024-09-11 19:05:37 +00:00
parent 06ab83eb50
commit 3f19805209
6 changed files with 140 additions and 7 deletions

View File

@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.android.settings.R; import com.android.settings.R;
@@ -101,6 +102,11 @@ public class AccessibilityActivityPreference extends RestrictedPreference {
return mLabel; return mLabel;
} }
@NonNull
public ComponentName getComponentName() {
return mComponentName;
}
private Drawable getA11yActivityIcon() { private Drawable getA11yActivityIcon() {
ActivityInfo activityInfo = mA11yShortcutInfo.getActivityInfo(); ActivityInfo activityInfo = mA11yShortcutInfo.getActivityInfo();
Drawable serviceIcon; Drawable serviceIcon;

View File

@@ -16,8 +16,12 @@
package com.android.settings.accessibility; package com.android.settings.accessibility;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import java.util.List; import java.util.List;
@@ -28,10 +32,22 @@ import java.util.List;
public interface AccessibilitySearchFeatureProvider { public interface AccessibilitySearchFeatureProvider {
/** /**
* Returns a list of raw data for indexing. See {@link SearchIndexableRaw} * Returns accessibility features to be searched where the accessibility features are always on
* the device and their feature names won't change.
* *
* @param context a valid context {@link Context} instance * @param context a valid context {@link Context} instance
* @return a list of {@link SearchIndexableRaw} references. Can be null. * @return a list of {@link SearchIndexableRaw} references
*/ */
@Nullable
List<SearchIndexableRaw> getSearchIndexableRawData(Context context); List<SearchIndexableRaw> getSearchIndexableRawData(Context context);
/**
* Returns synonyms of the Accessibility component that is used for search.
*
* @param context the context that is used for grabbing resources
* @param componentName the ComponentName of the accessibility feature
* @return a comma separated synonyms e.g. "wifi, wi-fi, network connection"
*/
@NonNull
String getSynonymsForComponent(@NonNull Context context, @NonNull ComponentName componentName);
} }

View File

@@ -16,8 +16,12 @@
package com.android.settings.accessibility; package com.android.settings.accessibility;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import java.util.List; import java.util.List;
@@ -27,8 +31,16 @@ import java.util.List;
*/ */
public class AccessibilitySearchFeatureProviderImpl implements AccessibilitySearchFeatureProvider { public class AccessibilitySearchFeatureProviderImpl implements AccessibilitySearchFeatureProvider {
@Nullable
@Override @Override
public List<SearchIndexableRaw> getSearchIndexableRawData(Context context) { public List<SearchIndexableRaw> getSearchIndexableRawData(Context context) {
return null; return null;
} }
@NonNull
@Override
public String getSynonymsForComponent(@NonNull Context context,
@NonNull ComponentName componentName) {
return "";
}
} }

View File

@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.android.settings.R; import com.android.settings.R;
@@ -95,6 +96,11 @@ public class AccessibilityServicePreference extends RestrictedPreference {
super.performClick(); super.performClick();
} }
@NonNull
public ComponentName getComponentName() {
return mComponentName;
}
private Drawable getA11yServiceIcon() { private Drawable getA11yServiceIcon() {
ResolveInfo resolveInfo = mA11yServiceInfo.getResolveInfo(); ResolveInfo resolveInfo = mA11yServiceInfo.getResolveInfo();
Drawable serviceIcon; Drawable serviceIcon;

View File

@@ -473,7 +473,7 @@ public class AccessibilitySettings extends DashboardFragment implements
* @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s. * @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s.
* @param installedServiceList A list of installed {@link AccessibilityServiceInfo}s. * @param installedServiceList A list of installed {@link AccessibilityServiceInfo}s.
*/ */
private List<RestrictedPreference> getInstalledAccessibilityPreferences(Context context, private static List<RestrictedPreference> getInstalledAccessibilityPreferences(Context context,
List<AccessibilityShortcutInfo> installedShortcutList, List<AccessibilityShortcutInfo> installedShortcutList,
List<AccessibilityServiceInfo> installedServiceList) { List<AccessibilityServiceInfo> installedServiceList) {
final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context); final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context);
@@ -623,6 +623,51 @@ public class AccessibilitySettings extends DashboardFragment implements
.getAccessibilitySearchFeatureProvider().getSearchIndexableRawData( .getAccessibilitySearchFeatureProvider().getSearchIndexableRawData(
context); context);
} }
@Override
public List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context,
boolean enabled) {
List<SearchIndexableRaw> dynamicRawData = super.getDynamicRawDataToIndex(
context, enabled);
if (dynamicRawData == null) {
dynamicRawData = new ArrayList<>();
}
if (!Flags.fixA11ySettingsSearch()) {
return dynamicRawData;
}
AccessibilityManager a11yManager = context.getSystemService(
AccessibilityManager.class);
AccessibilitySearchFeatureProvider a11ySearchFeatureProvider =
FeatureFactory.getFeatureFactory()
.getAccessibilitySearchFeatureProvider();
List<RestrictedPreference> installedA11yFeaturesPref =
AccessibilitySettings.getInstalledAccessibilityPreferences(
context,
a11yManager.getInstalledAccessibilityShortcutListAsUser(
context, UserHandle.myUserId()),
a11yManager.getInstalledAccessibilityServiceList()
);
for (RestrictedPreference pref : installedA11yFeaturesPref) {
SearchIndexableRaw indexableRaw = new SearchIndexableRaw(context);
indexableRaw.key = pref.getKey();
indexableRaw.title = pref.getTitle().toString();
@NonNull String synonyms = "";
if (pref instanceof AccessibilityServicePreference) {
synonyms = a11ySearchFeatureProvider.getSynonymsForComponent(
context,
((AccessibilityServicePreference) pref).getComponentName());
} else if (pref instanceof AccessibilityActivityPreference) {
synonyms = a11ySearchFeatureProvider.getSynonymsForComponent(
context,
((AccessibilityActivityPreference) pref).getComponentName());
}
indexableRaw.keywords = synonyms;
dynamicRawData.add(indexableRaw);
}
return dynamicRawData;
}
}; };
@Override @Override

View File

@@ -42,7 +42,6 @@ import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings; import android.provider.Settings;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.Flags;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
@@ -50,6 +49,7 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.accessibility.util.AccessibilityUtils;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.XmlTestUtils; import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowAccessibilityManager; import com.android.settings.testutils.shadow.ShadowAccessibilityManager;
import com.android.settings.testutils.shadow.ShadowApplicationPackageManager; import com.android.settings.testutils.shadow.ShadowApplicationPackageManager;
@@ -78,6 +78,7 @@ import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow; import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowContentResolver; import org.robolectric.shadows.ShadowContentResolver;
import org.robolectric.shadows.ShadowLooper;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
@@ -155,6 +156,53 @@ public class AccessibilitySettingsTest {
assertThat(indexableRawList).isNull(); assertThat(indexableRawList).isNull();
} }
@DisableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
@Test
public void getDynamicRawDataToIndex_hasInstalledA11yFeatures_flagOff_returnEmpty() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(mServiceInfo));
mShadowAccessibilityManager.setInstalledAccessibilityShortcutListAsUser(
List.of(getMockAccessibilityShortcutInfo()));
assertThat(AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex(
mContext, /* enabled= */ true))
.isEmpty();
}
@EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
@Test
public void getDynamicRawDataToIndex_hasInstalledA11yFeatures_flagOn_returnRawDataForInstalledA11yFeatures() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(mServiceInfo));
mShadowAccessibilityManager.setInstalledAccessibilityShortcutListAsUser(
List.of(getMockAccessibilityShortcutInfo()));
final AccessibilitySearchFeatureProvider featureProvider =
FakeFeatureFactory.setupForTest().getAccessibilitySearchFeatureProvider();
final String synonyms = "fake keyword1, fake keyword2";
when(featureProvider.getSynonymsForComponent(mContext, ACTIVITY_COMPONENT_NAME))
.thenReturn("");
when(featureProvider.getSynonymsForComponent(mContext, SERVICE_COMPONENT_NAME))
.thenReturn(synonyms);
final List<SearchIndexableRaw> indexableRawDataList =
AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER.getDynamicRawDataToIndex(
mContext, /* enabled= */ true);
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
assertThat(indexableRawDataList).hasSize(2);
SearchIndexableRaw a11yActivityIndexableData = indexableRawDataList.get(0);
assertThat(a11yActivityIndexableData.key).isEqualTo(
ACTIVITY_COMPONENT_NAME.flattenToString());
assertThat(a11yActivityIndexableData.title).isEqualTo(DEFAULT_LABEL);
assertThat(a11yActivityIndexableData.keywords).isEmpty();
SearchIndexableRaw a11yServiceIndexableData = indexableRawDataList.get(1);
assertThat(a11yServiceIndexableData.key).isEqualTo(
SERVICE_COMPONENT_NAME.flattenToString());
assertThat(a11yServiceIndexableData.title).isEqualTo(DEFAULT_LABEL);
assertThat(a11yServiceIndexableData.keywords).isEqualTo(synonyms);
}
@Test @Test
public void getServiceSummary_serviceCrash_showsStopped() { public void getServiceSummary_serviceCrash_showsStopped() {
mServiceInfo.crashed = true; mServiceInfo.crashed = true;
@@ -328,7 +376,7 @@ public class AccessibilitySettingsTest {
} }
@Test @Test
@DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void onCreate_flagDisabled_haveRegisterToSpecificUrisAndActions() { public void onCreate_flagDisabled_haveRegisterToSpecificUrisAndActions() {
setupFragment(); setupFragment();
@@ -341,7 +389,7 @@ public class AccessibilitySettingsTest {
} }
@Test @Test
@EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void onCreate_flagEnabled_haveRegisterToSpecificUrisAndActions() { public void onCreate_flagEnabled_haveRegisterToSpecificUrisAndActions() {
setupFragment(); setupFragment();
@@ -415,7 +463,7 @@ public class AccessibilitySettingsTest {
} }
@Test @Test
@EnableFlags(com.android.settings.accessibility.Flags.FLAG_CHECK_PREBUNDLED_IS_PREINSTALLED) @EnableFlags(Flags.FLAG_CHECK_PREBUNDLED_IS_PREINSTALLED)
public void testNonPreinstalledApp_IncludedInDownloadedCategory() { public void testNonPreinstalledApp_IncludedInDownloadedCategory() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList( mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(getMockAccessibilityServiceInfo( List.of(getMockAccessibilityServiceInfo(