feat(A11yFeedback): Add feedback entry for downloaded Accessibility
This entry point allows users to access in the action bar. Visibility is controlled by the aconfig and FeedbackManager#isAvailable Bug: 393980229 Test: Manual testing on Pixel and non-Pixel devices Test: atest ToggleFeaturePreferenceFragmentTest Flag: com.android.server.accessibility.enable_low_vision_generic_feedback Change-Id: Ie6dfb6a887fe5a894622e86bab39878f8adea758
This commit is contained in:
@@ -232,6 +232,7 @@ public class AccessibilityDetailsSettingsFragment extends InstrumentedFragment {
|
|||||||
.getAccessibilityMetricsFeatureProvider()
|
.getAccessibilityMetricsFeatureProvider()
|
||||||
.getDownloadedFeatureMetricsCategory(componentName);
|
.getDownloadedFeatureMetricsCategory(componentName);
|
||||||
extras.putInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY, metricsCategory);
|
extras.putInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY, metricsCategory);
|
||||||
|
extras.putInt(AccessibilitySettings.EXTRA_FEEDBACK_CATEGORY, metricsCategory);
|
||||||
extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
|
extras.putParcelable(AccessibilitySettings.EXTRA_COMPONENT_NAME, componentName);
|
||||||
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, info.getAnimatedImageRes());
|
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, info.getAnimatedImageRes());
|
||||||
|
|
||||||
|
@@ -97,6 +97,7 @@ public class AccessibilitySettings extends DashboardFragment implements
|
|||||||
static final String EXTRA_HTML_DESCRIPTION = "html_description";
|
static final String EXTRA_HTML_DESCRIPTION = "html_description";
|
||||||
static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
|
static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
|
||||||
static final String EXTRA_METRICS_CATEGORY = "metrics_category";
|
static final String EXTRA_METRICS_CATEGORY = "metrics_category";
|
||||||
|
static final String EXTRA_FEEDBACK_CATEGORY = "feedback_category";
|
||||||
|
|
||||||
// Timeout before we update the services if packages are added/removed
|
// Timeout before we update the services if packages are added/removed
|
||||||
// since the AccessibilityManagerService has to do that processing first
|
// since the AccessibilityManagerService has to do that processing first
|
||||||
|
@@ -57,6 +57,11 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
|
|||||||
return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
|
return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFeedbackCategory() {
|
||||||
|
return getArguments().getInt(AccessibilitySettings.EXTRA_FEEDBACK_CATEGORY);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
@@ -217,6 +217,7 @@ public class RestrictedPreferenceHelper {
|
|||||||
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, imageRes);
|
extras.putInt(AccessibilitySettings.EXTRA_ANIMATED_IMAGE_RES, imageRes);
|
||||||
extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription);
|
extras.putString(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, htmlDescription);
|
||||||
extras.putInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY, metricsCategory);
|
extras.putInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY, metricsCategory);
|
||||||
|
extras.putInt(AccessibilitySettings.EXTRA_FEEDBACK_CATEGORY, metricsCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -73,6 +73,11 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
|||||||
return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
|
return getArguments().getInt(AccessibilitySettings.EXTRA_METRICS_CATEGORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFeedbackCategory() {
|
||||||
|
return getArguments().getInt(AccessibilitySettings.EXTRA_FEEDBACK_CATEGORY);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@@ -40,6 +40,9 @@ import android.service.quicksettings.TileService;
|
|||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
@@ -48,6 +51,7 @@ import android.widget.CompoundButton;
|
|||||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -89,6 +93,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
// <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
|
// <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
|
||||||
private static final String IMG_PREFIX = "R.drawable.";
|
private static final String IMG_PREFIX = "R.drawable.";
|
||||||
private static final String DRAWABLE_FOLDER = "drawable";
|
private static final String DRAWABLE_FOLDER = "drawable";
|
||||||
|
static final int MENU_ID_SEND_FEEDBACK = 0;
|
||||||
|
|
||||||
protected TopIntroPreference mTopIntroPreference;
|
protected TopIntroPreference mTopIntroPreference;
|
||||||
protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
|
protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
|
||||||
@@ -102,6 +107,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
protected Intent mSettingsIntent;
|
protected Intent mSettingsIntent;
|
||||||
// The mComponentName maybe null, such as Magnify
|
// The mComponentName maybe null, such as Magnify
|
||||||
protected ComponentName mComponentName;
|
protected ComponentName mComponentName;
|
||||||
|
@Nullable private FeedbackManager mFeedbackManager;
|
||||||
protected CharSequence mFeatureName;
|
protected CharSequence mFeatureName;
|
||||||
protected Uri mImageUri;
|
protected Uri mImageUri;
|
||||||
protected CharSequence mHtmlDescription;
|
protected CharSequence mHtmlDescription;
|
||||||
@@ -240,6 +246,24 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
removeActionBarToggleSwitch();
|
removeActionBarToggleSwitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||||
|
if (getFeedbackManager().isAvailable()) {
|
||||||
|
menu.add(Menu.NONE, MENU_ID_SEND_FEEDBACK, Menu.NONE,
|
||||||
|
R.string.accessibility_send_feedback_title);
|
||||||
|
}
|
||||||
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
|
if (item.getItemId() == MENU_ID_SEND_FEEDBACK) {
|
||||||
|
getFeedbackManager().sendFeedback();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDialogMetricsCategory(int dialogId) {
|
public int getDialogMetricsCategory(int dialogId) {
|
||||||
switch (dialogId) {
|
switch (dialogId) {
|
||||||
@@ -739,4 +763,28 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
super.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
super.onCreateRecyclerView(inflater, parent, savedInstanceState);
|
||||||
return AccessibilityFragmentUtils.addCollectionInfoToAccessibilityDelegate(recyclerView);
|
return AccessibilityFragmentUtils.addCollectionInfoToAccessibilityDelegate(recyclerView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setFeedbackManager(FeedbackManager feedbackManager) {
|
||||||
|
this.mFeedbackManager = feedbackManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FeedbackManager getFeedbackManager() {
|
||||||
|
if (mFeedbackManager == null) {
|
||||||
|
mFeedbackManager = new FeedbackManager(getActivity(), getFeedbackCategory());
|
||||||
|
}
|
||||||
|
return mFeedbackManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the category of the feedback page.
|
||||||
|
*
|
||||||
|
* <p>By default, this method returns {@link SettingsEnums#PAGE_UNKNOWN}. This indicates that
|
||||||
|
* the feedback category is unknown, and the absence of a feedback menu.
|
||||||
|
*
|
||||||
|
* @return The feedback category, which is {@link SettingsEnums#PAGE_UNKNOWN} by default.
|
||||||
|
*/
|
||||||
|
protected int getFeedbackCategory() {
|
||||||
|
return SettingsEnums.PAGE_UNKNOWN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,6 +79,12 @@ public class ToggleScreenReaderPreferenceFragmentForSetupWizard
|
|||||||
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER;
|
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFeedbackCategory() {
|
||||||
|
// The feedback options should not be displayed on the setup wizard page.
|
||||||
|
return SettingsEnums.PAGE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
// Log the final choice in value if it's different from the previous value.
|
// Log the final choice in value if it's different from the previous value.
|
||||||
|
@@ -79,6 +79,12 @@ public class ToggleSelectToSpeakPreferenceFragmentForSetupWizard
|
|||||||
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK;
|
return SettingsEnums.SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFeedbackCategory() {
|
||||||
|
// The feedback options should not be displayed on the setup wizard page.
|
||||||
|
return SettingsEnums.PAGE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
// Log the final choice in value if it's different from the previous value.
|
// Log the final choice in value if it's different from the previous value.
|
||||||
|
@@ -23,9 +23,12 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
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;
|
||||||
@@ -37,10 +40,13 @@ import android.content.Intent;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.icu.text.CaseMap;
|
import android.icu.text.CaseMap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
import android.platform.test.annotations.EnableFlags;
|
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.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
@@ -66,8 +72,9 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Answers;
|
import org.mockito.Answers;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadow.api.Shadow;
|
import org.robolectric.shadow.api.Shadow;
|
||||||
@@ -83,6 +90,8 @@ import java.util.Locale;
|
|||||||
ShadowAccessibilityManager.class
|
ShadowAccessibilityManager.class
|
||||||
})
|
})
|
||||||
public class ToggleFeaturePreferenceFragmentTest {
|
public class ToggleFeaturePreferenceFragmentTest {
|
||||||
|
@Rule
|
||||||
|
public final MockitoRule mocks = MockitoJUnit.rule();
|
||||||
@Rule
|
@Rule
|
||||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
|
|
||||||
@@ -96,6 +105,7 @@ public class ToggleFeaturePreferenceFragmentTest {
|
|||||||
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
|
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
|
||||||
private static final String PLACEHOLDER_TILE_TOOLTIP_CONTENT =
|
private static final String PLACEHOLDER_TILE_TOOLTIP_CONTENT =
|
||||||
PLACEHOLDER_PACKAGE_NAME + "tooltip_content";
|
PLACEHOLDER_PACKAGE_NAME + "tooltip_content";
|
||||||
|
private static final String PLACEHOLDER_CATEGORY = "category";
|
||||||
private static final String PLACEHOLDER_DIALOG_TITLE = "title";
|
private static final String PLACEHOLDER_DIALOG_TITLE = "title";
|
||||||
private static final String DEFAULT_SUMMARY = "default summary";
|
private static final String DEFAULT_SUMMARY = "default summary";
|
||||||
private static final String DEFAULT_DESCRIPTION = "default description";
|
private static final String DEFAULT_DESCRIPTION = "default description";
|
||||||
@@ -120,10 +130,13 @@ public class ToggleFeaturePreferenceFragmentTest {
|
|||||||
private ContentResolver mContentResolver;
|
private ContentResolver mContentResolver;
|
||||||
@Mock
|
@Mock
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
private Menu mMenu;
|
||||||
|
@Mock
|
||||||
|
private MenuItem mMenuItem;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUpTestFragment() {
|
public void setUpTestFragment() {
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
mShadowAccessibilityManager = Shadow.extract(
|
mShadowAccessibilityManager = Shadow.extract(
|
||||||
mContext.getSystemService(AccessibilityManager.class));
|
mContext.getSystemService(AccessibilityManager.class));
|
||||||
|
|
||||||
@@ -169,6 +182,61 @@ public class ToggleFeaturePreferenceFragmentTest {
|
|||||||
any(AccessibilitySettingsContentObserver.class));
|
any(AccessibilitySettingsContentObserver.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
|
||||||
|
public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
|
||||||
|
mFragment.setFeedbackManager(
|
||||||
|
new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
|
||||||
|
|
||||||
|
mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
|
||||||
|
|
||||||
|
verify(mMenu).add(anyInt(), eq(ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK),
|
||||||
|
anyInt(), eq(R.string.accessibility_send_feedback_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
|
||||||
|
public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
|
||||||
|
mFragment.setFeedbackManager(
|
||||||
|
new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
|
||||||
|
|
||||||
|
mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
|
||||||
|
|
||||||
|
verify(mMenu, never()).add(anyInt(),
|
||||||
|
eq(ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK), anyInt(),
|
||||||
|
eq(R.string.accessibility_send_feedback_title));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
|
||||||
|
public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
|
||||||
|
mFragment.setFeedbackManager(
|
||||||
|
new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
|
||||||
|
when(mMenuItem.getItemId()).thenReturn(
|
||||||
|
ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK);
|
||||||
|
|
||||||
|
mFragment.onOptionsItemSelected(mMenuItem);
|
||||||
|
|
||||||
|
verify(mActivity).startActivityForResult(
|
||||||
|
argThat(intent -> intent != null
|
||||||
|
&& Intent.ACTION_BUG_REPORT.equals(intent.getAction())), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
|
||||||
|
public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
|
||||||
|
mFragment.setFeedbackManager(
|
||||||
|
new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
|
||||||
|
when(mMenuItem.getItemId()).thenReturn(
|
||||||
|
ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK);
|
||||||
|
|
||||||
|
mFragment.onOptionsItemSelected(mMenuItem);
|
||||||
|
|
||||||
|
verify(mActivity, never()).startActivityForResult(
|
||||||
|
argThat(intent -> intent != null
|
||||||
|
&& Intent.ACTION_BUG_REPORT.equals(intent.getAction())), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateShortcutPreferenceData_assignDefaultValueToVariable() {
|
public void updateShortcutPreferenceData_assignDefaultValueToVariable() {
|
||||||
mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
|
mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
|
||||||
|
Reference in New Issue
Block a user