Integrate Accessibility quick setting tooltips widget into ToggleFeaturePreferenceFragment

- Show tooltips when main switch is on
- Reshow tooltips when rotate device
- Add abstract functions for child components to show tooltips

Bug: 210356011
Test: make RunSettingsRoboTests ROBOTEST_FILTER=ToggleFeaturePreferenceFragmentTest
Change-Id: I543d8af7d24a9fc82659625961850f975a7a0787
This commit is contained in:
menghanli
2022-01-24 13:06:54 +08:00
parent d329f3d79c
commit ba9f097b03
8 changed files with 209 additions and 10 deletions

View File

@@ -114,6 +114,16 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature
mComponentName);
}
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileName() {
return null;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Do not call super. We don't want to see the "Help & feedback" option on this page so as

View File

@@ -241,6 +241,16 @@ public class ToggleAccessibilityServicePreferenceFragment extends
mComponentName);
}
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileName() {
return null;
}
@Override
protected void updateSwitchBarToggleSwitch() {
final boolean checked = isAccessibilityServiceEnabled();

View File

@@ -22,6 +22,7 @@ import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;
@@ -131,6 +132,16 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere
mComponentName);
}
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileName() {
return null;
}
@Override
protected void updateSwitchBarToggleSwitch() {
final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;

View File

@@ -22,6 +22,7 @@ import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
@@ -181,6 +182,16 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe
mComponentName);
}
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileName() {
return null;
}
@Override
protected void updateSwitchBarToggleSwitch() {
final boolean checked = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;

View File

@@ -96,6 +96,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
protected static final String KEY_HTML_DESCRIPTION_PREFERENCE = "html_description";
private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
protected static final String KEY_SAVED_USER_SHORTCUT_TYPE = "shortcut_type";
protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
protected static final String KEY_ANIMATED_IMAGE = "animated_image";
private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
@@ -104,6 +105,9 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
private CheckBox mSoftwareTypeCheckBox;
private CheckBox mHardwareTypeCheckBox;
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
private boolean mNeedsQSTooltipReshow = false;
public static final int NOT_SET = -1;
// Save user's shortcutType value when savedInstance has value (e.g. device rotated).
protected int mSavedCheckBoxValue = NOT_SET;
@@ -129,10 +133,15 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Restore the user shortcut type.
if (savedInstanceState != null && savedInstanceState.containsKey(
KEY_SAVED_USER_SHORTCUT_TYPE)) {
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE, NOT_SET);
// Restore the user shortcut type and tooltip.
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(KEY_SAVED_USER_SHORTCUT_TYPE)) {
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE,
NOT_SET);
}
if (savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_RESHOW)) {
mNeedsQSTooltipReshow = savedInstanceState.getBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW);
}
}
setupDefaultShortcutIfNecessary(getPrefContext());
@@ -198,6 +207,11 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
switchBar.hide();
updatePreferenceOrder();
// Reshow tooltips when activity recreate, such as rotate device.
if (mNeedsQSTooltipReshow) {
getView().post(this::showQuickSettingsTooltipIfNeeded);
}
}
@Override
@@ -231,6 +245,9 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
if (value != NOT_SET) {
outState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, value);
}
if (mTooltipWindow != null) {
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, mTooltipWindow.isShowing());
}
super.onSaveInstanceState(outState);
}
@@ -296,6 +313,12 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
*/
abstract int getUserShortcutTypes();
/** Returns the accessibility tile component name. */
abstract ComponentName getTileComponentName();
/** Returns the accessibility tile feature name. */
abstract CharSequence getTileName();
protected void updateToggleServiceTitle(SettingsMainSwitchPreference switchPreference) {
final CharSequence title =
getString(R.string.accessibility_service_primary_switch_title, mPackageName);
@@ -307,7 +330,11 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
shortcutPreference.setTitle(title);
}
protected abstract void onPreferenceToggled(String preferenceKey, boolean enabled);
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
if (enabled) {
showQuickSettingsTooltipIfNeeded();
}
}
protected void onInstallSwitchPreferenceToggleSwitch() {
// Implement this to set a checked listener.
@@ -770,4 +797,37 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
mComponentName.flattenToString(), type);
PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
}
/**
* Shows the quick settings tooltip if the quick settings service is assigned. The tooltip only
* shows once.
*/
protected void showQuickSettingsTooltipIfNeeded() {
final ComponentName tileComponentName = getTileComponentName();
if (tileComponentName == null) {
// Returns if no tile service assigned.
return;
}
if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
getContext(), tileComponentName)) {
// Returns if quick settings tooltip only show once.
return;
}
final CharSequence tileName = getTileName();
if (TextUtils.isEmpty(tileName)) {
// Returns if no title of tile service assigned.
return;
}
final String title =
getString(R.string.accessibility_service_quick_settings_tooltips_content, tileName);
mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(getContext());
mTooltipWindow.setup(title);
mTooltipWindow.showAtTopCenter(getView());
AccessibilityQuickSettingUtils.optInValueToSharedPreferences(getContext(),
tileComponentName);
mNeedsQSTooltipReshow = false;
}
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.accessibility;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.hardware.display.ColorDisplayManager;
@@ -169,6 +170,16 @@ public class ToggleReduceBrightColorsPreferenceFragment extends ToggleFeaturePre
mComponentName);
}
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileName() {
return null;
}
@Override
protected void updateSwitchBarToggleSwitch() {
final boolean checked = mColorDisplayManager.isReduceBrightColorsActivated();

View File

@@ -23,6 +23,7 @@ import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -398,6 +399,16 @@ public class ToggleScreenMagnificationPreferenceFragment extends
return getUserShortcutTypeFromSettings(getPrefContext());
}
@Override
ComponentName getTileComponentName() {
return null;
}
@Override
CharSequence getTileName() {
return null;
}
@Override
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
if (enabled && TextUtils.equals(

View File

@@ -16,6 +16,7 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_QS_TOOLTIP_RESHOW;
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_USER_SHORTCUT_TYPE;
import static com.google.common.truth.Truth.assertThat;
@@ -37,6 +38,7 @@ import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import androidx.annotation.XmlRes;
import androidx.appcompat.app.AlertDialog;
@@ -58,6 +60,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.androidx.fragment.FragmentController;
/** Tests for {@link ToggleFeaturePreferenceFragment} */
@@ -68,6 +72,12 @@ public class ToggleFeaturePreferenceFragmentTest {
private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder";
private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME);
private static final String PLACEHOLDER_TILE_CLASS_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
private static final String PLACEHOLDER_TILE_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final String PLACEHOLDER_DIALOG_TITLE = "title";
private static final String DEFAULT_SUMMARY = "default summary";
private static final String DEFAULT_DESCRIPTION = "default description";
@@ -211,7 +221,7 @@ public class ToggleFeaturePreferenceFragmentTest {
@Test
@Config(shadows = ShadowFragment.class)
public void restoreValueFromSavedInstanceState_assignToVariable() {
public void restoreValueFromSavedInstanceState_assignShortcutTypeToVariable() {
mContext.setTheme(R.style.Theme_AppCompat);
final AlertDialog dialog = AccessibilityDialogUtils.showEditShortcutDialog(
mContext, DialogType.EDIT_SHORTCUT_GENERIC, PLACEHOLDER_DIALOG_TITLE,
@@ -234,6 +244,55 @@ public class ToggleFeaturePreferenceFragmentTest {
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}
@Test
@Config(shadows = ShadowFragment.class)
public void onPreferenceToggledOnDisabledService_notShowTooltipView() {
mContext.setTheme(R.style.Theme_AppCompat);
mFragment.onPreferenceToggled(mFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ false);
assertThat(getLatestPopupWindow()).isNull();
}
@Test
@Config(shadows = ShadowFragment.class)
public void onPreferenceToggledOnEnabledService_showTooltipView() {
mContext.setTheme(R.style.Theme_AppCompat);
mFragment.onPreferenceToggled(mFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true);
assertThat(getLatestPopupWindow().isShowing()).isTrue();
}
@Test
@Config(shadows = ShadowFragment.class)
public void onPreferenceToggledOnEnabledService_tooltipViewShown_notShowTooltipView() {
mContext.setTheme(R.style.Theme_AppCompat);
mFragment.onPreferenceToggled(mFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true);
getLatestPopupWindow().dismiss();
mFragment.onPreferenceToggled(mFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true);
assertThat(getLatestPopupWindow().isShowing()).isFalse();
}
@Test
@Config(shadows = ShadowFragment.class)
public void restoreValueFromSavedInstanceState_showTooltipView() {
mContext.setTheme(R.style.Theme_AppCompat);
mFragment.onPreferenceToggled(mFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true);
assertThat(getLatestPopupWindow().isShowing()).isTrue();
final Bundle savedInstanceState = new Bundle();
savedInstanceState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
mFragment.onCreate(savedInstanceState);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onViewCreated(mFragment.getView(), savedInstanceState);
mFragment.onAttach(mContext);
assertThat(getLatestPopupWindow().isShowing()).isTrue();
}
@Test
public void createFooterPreference_shouldSetAsExpectedValue() {
mFragment.createFooterPreference(mFragment.getPreferenceScreen(),
@@ -258,13 +317,15 @@ public class ToggleFeaturePreferenceFragmentTest {
private void callEmptyOnClicked(DialogInterface dialog, int which) {}
private static PopupWindow getLatestPopupWindow() {
final ShadowApplication shadowApplication =
Shadow.extract(ApplicationProvider.getApplicationContext());
return shadowApplication.getLatestPopupWindow();
}
public static class TestToggleFeaturePreferenceFragment
extends ToggleFeaturePreferenceFragment {
@Override
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
}
@Override
public int getMetricsCategory() {
return 0;
@@ -275,6 +336,16 @@ public class ToggleFeaturePreferenceFragmentTest {
return 0;
}
@Override
ComponentName getTileComponentName() {
return PLACEHOLDER_TILE_COMPONENT_NAME;
}
@Override
CharSequence getTileName() {
return PLACEHOLDER_TILE_NAME;
}
@Override
public int getPreferenceScreenResId() {
return R.xml.placeholder_prefs;
@@ -306,5 +377,9 @@ public class ToggleFeaturePreferenceFragmentTest {
// UI related function, do nothing in tests
}
@Override
public View getView() {
return mock(View.class);
}
}
}