Support OHM quick settings tooltips when feature on

Bug: 210356011
Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityShortcutPreferenceFragmentTest
Change-Id: I3b35d9bb347b7e516db94a4b801a4484f6f38ca8
This commit is contained in:
menghanli
2022-01-25 05:58:33 +08:00
parent 6892e89775
commit 95eba64f85
3 changed files with 167 additions and 38 deletions

View File

@@ -28,6 +28,7 @@ import android.icu.text.CaseMap;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -56,6 +57,7 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
implements ShortcutPreference.OnClickCallback { implements ShortcutPreference.OnClickCallback {
private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference"; 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_USER_SHORTCUT_TYPE = "shortcut_type";
protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
protected static final int NOT_SET = -1; protected static final int NOT_SET = -1;
// Save user's shortcutType value when savedInstance has value (e.g. device rotated). // Save user's shortcutType value when savedInstance has value (e.g. device rotated).
protected int mSavedCheckBoxValue = NOT_SET; protected int mSavedCheckBoxValue = NOT_SET;
@@ -66,6 +68,8 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
private AccessibilitySettingsContentObserver mSettingsContentObserver; private AccessibilitySettingsContentObserver mSettingsContentObserver;
private CheckBox mSoftwareTypeCheckBox; private CheckBox mSoftwareTypeCheckBox;
private CheckBox mHardwareTypeCheckBox; private CheckBox mHardwareTypeCheckBox;
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
private boolean mNeedsQSTooltipReshow = false;
/** Returns the accessibility component name. */ /** Returns the accessibility component name. */
protected abstract ComponentName getComponentName(); protected abstract ComponentName getComponentName();
@@ -73,14 +77,25 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
/** Returns the accessibility feature name. */ /** Returns the accessibility feature name. */
protected abstract CharSequence getLabelName(); protected abstract CharSequence getLabelName();
/** Returns the accessibility tile component name. */
protected abstract ComponentName getTileComponentName();
/** Returns the accessibility tile feature name. */
protected abstract CharSequence getTileName();
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Restore the user shortcut type. // Restore the user shortcut type and tooltip.
if (savedInstanceState != null && savedInstanceState.containsKey( if (savedInstanceState != null) {
KEY_SAVED_USER_SHORTCUT_TYPE)) { if (savedInstanceState.containsKey(KEY_SAVED_USER_SHORTCUT_TYPE)) {
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE, NOT_SET); 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);
}
} }
final int resId = getPreferenceScreenResId(); final int resId = getPreferenceScreenResId();
@@ -123,6 +138,16 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
return super.onCreateView(inflater, container, savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState);
} }
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Reshow tooltips when activity recreate, such as rotate device.
if (mNeedsQSTooltipReshow) {
getView().post(this::showQuickSettingsTooltipIfNeeded);
}
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@@ -149,6 +174,9 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
if (value != NOT_SET) { if (value != NOT_SET) {
outState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, value); outState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, value);
} }
if (mTooltipWindow != null) {
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, mTooltipWindow.isShowing());
}
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
@@ -423,4 +451,33 @@ public abstract class AccessibilityShortcutPreferenceFragment extends DashboardF
getComponentName())); getComponentName()));
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
} }
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

@@ -29,6 +29,7 @@ import com.android.settings.accessibility.AccessibilityShortcutPreferenceFragmen
import com.android.settings.accessibility.ShortcutPreference; import com.android.settings.accessibility.ShortcutPreference;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.widget.IllustrationPreference; import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.MainSwitchPreference;
/** /**
* Fragment for One-handed mode settings * Fragment for One-handed mode settings
@@ -40,6 +41,8 @@ public class OneHandedSettings extends AccessibilityShortcutPreferenceFragment {
private static final String ONE_HANDED_SHORTCUT_KEY = "one_handed_shortcuts_preference"; private static final String ONE_HANDED_SHORTCUT_KEY = "one_handed_shortcuts_preference";
private static final String ONE_HANDED_ILLUSTRATION_KEY = "one_handed_header"; private static final String ONE_HANDED_ILLUSTRATION_KEY = "one_handed_header";
protected static final String ONE_HANDED_MAIN_SWITCH_KEY =
"gesture_one_handed_mode_enabled_main_switch";
private String mFeatureName; private String mFeatureName;
private OneHandedSettingsUtils mUtils; private OneHandedSettingsUtils mUtils;
@@ -48,16 +51,22 @@ public class OneHandedSettings extends AccessibilityShortcutPreferenceFragment {
OneHandedSettingsUtils.setUserId(UserHandle.myUserId()); OneHandedSettingsUtils.setUserId(UserHandle.myUserId());
super.updatePreferenceStates(); super.updatePreferenceStates();
final IllustrationPreference preference = final IllustrationPreference illustrationPreference =
(IllustrationPreference) getPreferenceScreen().findPreference( getPreferenceScreen().findPreference(ONE_HANDED_ILLUSTRATION_KEY);
ONE_HANDED_ILLUSTRATION_KEY); final boolean isSwipeDownNotification =
if (preference != null) { OneHandedSettingsUtils.isSwipeDownNotificationEnabled(getContext());
final boolean isSwipeDownNotification = illustrationPreference.setLottieAnimationResId(
OneHandedSettingsUtils.isSwipeDownNotificationEnabled(getContext()); isSwipeDownNotification ? R.raw.lottie_swipe_for_notifications
preference.setLottieAnimationResId( : R.raw.lottie_one_hand_mode);
isSwipeDownNotification ? R.raw.lottie_swipe_for_notifications
: R.raw.lottie_one_hand_mode); final MainSwitchPreference mainSwitchPreference =
} getPreferenceScreen().findPreference(ONE_HANDED_MAIN_SWITCH_KEY);
mainSwitchPreference.addOnSwitchChangeListener((switchView, isChecked) -> {
switchView.setChecked(isChecked);
if (isChecked) {
showQuickSettingsTooltipIfNeeded();
}
});
} }
@Override @Override
@@ -115,6 +124,16 @@ public class OneHandedSettings extends AccessibilityShortcutPreferenceFragment {
return mFeatureName; return mFeatureName;
} }
@Override
protected ComponentName getTileComponentName() {
return AccessibilityShortcutController.ONE_HANDED_TILE_COMPONENT_NAME;
}
@Override
protected CharSequence getTileName() {
return mFeatureName;
}
@Override @Override
protected int getPreferenceScreenResId() { protected int getPreferenceScreenResId() {
return R.xml.one_handed_settings; return R.xml.one_handed_settings;

View File

@@ -16,11 +16,14 @@
package com.android.settings.accessibility; package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment.KEY_SAVED_QS_TOOLTIP_RESHOW;
import static com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment.KEY_SAVED_USER_SHORTCUT_TYPE; import static com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment.KEY_SAVED_USER_SHORTCUT_TYPE;
import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
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;
@@ -30,6 +33,10 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.provider.Settings; import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
@@ -48,6 +55,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
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.shadows.ShadowApplication;
/** Tests for {@link AccessibilityShortcutPreferenceFragment} */ /** Tests for {@link AccessibilityShortcutPreferenceFragment} */
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@@ -55,8 +64,12 @@ public class AccessibilityShortcutPreferenceFragmentTest {
private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder"; private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder";
private static final String PLACEHOLDER_TILE_CLASS_NAME =
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName( private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME); PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME);
private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
private static final String PLACEHOLDER_DIALOG_TITLE = "title"; private static final String PLACEHOLDER_DIALOG_TITLE = "title";
private static final String SOFTWARE_SHORTCUT_KEY = private static final String SOFTWARE_SHORTCUT_KEY =
@@ -89,10 +102,9 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.updateShortcutPreferenceData(); mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
AccessibilityUtil.UserShortcutType.SOFTWARE);
// Compare to default UserShortcutType // Compare to default UserShortcutType
assertThat(expectedType).isEqualTo(AccessibilityUtil.UserShortcutType.SOFTWARE); assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE);
} }
@Test @Test
@@ -103,25 +115,21 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.updateShortcutPreferenceData(); mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
AccessibilityUtil.UserShortcutType.SOFTWARE); assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
assertThat(expectedType).isEqualTo(AccessibilityUtil.UserShortcutType.SOFTWARE
| AccessibilityUtil.UserShortcutType.HARDWARE);
} }
@Test @Test
public void updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable() { public void updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable() {
final PreferredShortcut hardwareShortcut = new PreferredShortcut( final PreferredShortcut hardwareShortcut = new PreferredShortcut(
PLACEHOLDER_COMPONENT_NAME.flattenToString(), PLACEHOLDER_COMPONENT_NAME.flattenToString(), UserShortcutType.HARDWARE);
AccessibilityUtil.UserShortcutType.HARDWARE);
putUserShortcutTypeIntoSharedPreference(mContext, hardwareShortcut); putUserShortcutTypeIntoSharedPreference(mContext, hardwareShortcut);
mFragment.updateShortcutPreferenceData(); mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
AccessibilityUtil.UserShortcutType.SOFTWARE); assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE);
assertThat(expectedType).isEqualTo(AccessibilityUtil.UserShortcutType.HARDWARE);
} }
@Test @Test
@@ -139,7 +147,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.setupEditShortcutDialog(dialog); mFragment.setupEditShortcutDialog(dialog);
final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue(); final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue();
assertThat(checkboxValue).isEqualTo(AccessibilityUtil.UserShortcutType.EMPTY); assertThat(checkboxValue).isEqualTo(UserShortcutType.EMPTY);
} }
@Test @Test
@@ -152,8 +160,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */ final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */
null); null);
final PreferredShortcut hardwareShortcut = new PreferredShortcut( final PreferredShortcut hardwareShortcut = new PreferredShortcut(
PLACEHOLDER_COMPONENT_NAME.flattenToString(), PLACEHOLDER_COMPONENT_NAME.flattenToString(), UserShortcutType.HARDWARE);
AccessibilityUtil.UserShortcutType.HARDWARE);
mFragment.mShortcutPreference = shortcutPreference; mFragment.mShortcutPreference = shortcutPreference;
PreferredShortcuts.saveUserShortcutType(mContext, hardwareShortcut); PreferredShortcuts.saveUserShortcutType(mContext, hardwareShortcut);
@@ -161,12 +168,12 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.setupEditShortcutDialog(dialog); mFragment.setupEditShortcutDialog(dialog);
final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue(); final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue();
assertThat(checkboxValue).isEqualTo(AccessibilityUtil.UserShortcutType.HARDWARE); assertThat(checkboxValue).isEqualTo(UserShortcutType.HARDWARE);
} }
@Test @Test
@Config(shadows = ShadowFragment.class) @Config(shadows = ShadowFragment.class)
public void restoreValueFromSavedInstanceState_assignToVariable() { public void restoreValueFromSavedInstanceState_assignShortcutTypeToVariable() {
mContext.setTheme(R.style.Theme_AppCompat); mContext.setTheme(R.style.Theme_AppCompat);
final AlertDialog dialog = AccessibilityDialogUtils.showEditShortcutDialog( final AlertDialog dialog = AccessibilityDialogUtils.showEditShortcutDialog(
mContext, AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC, mContext, AccessibilityDialogUtils.DialogType.EDIT_SHORTCUT_GENERIC,
@@ -178,8 +185,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.mShortcutPreference = shortcutPreference; mFragment.mShortcutPreference = shortcutPreference;
savedInstanceState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, savedInstanceState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE,
AccessibilityUtil.UserShortcutType.SOFTWARE UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
| AccessibilityUtil.UserShortcutType.HARDWARE);
mFragment.onAttach(mContext); mFragment.onAttach(mContext);
mFragment.onCreate(savedInstanceState); mFragment.onCreate(savedInstanceState);
mFragment.setupEditShortcutDialog(dialog); mFragment.setupEditShortcutDialog(dialog);
@@ -187,11 +193,25 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.saveNonEmptyUserShortcutType(value); mFragment.saveNonEmptyUserShortcutType(value);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
AccessibilityUtil.UserShortcutType.SOFTWARE); assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
assertThat(expectedType).isEqualTo( }
AccessibilityUtil.UserShortcutType.SOFTWARE
| AccessibilityUtil.UserShortcutType.HARDWARE); @Test
@Config(shadows = ShadowFragment.class)
public void restoreValueFromSavedInstanceState_showTooltipView() {
mContext.setTheme(R.style.Theme_AppCompat);
mFragment.showQuickSettingsTooltipIfNeeded();
assertThat(getLatestPopupWindow().isShowing()).isTrue();
final Bundle savedInstanceState = new Bundle();
savedInstanceState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
mFragment.onAttach(mContext);
mFragment.onCreate(savedInstanceState);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onViewCreated(mFragment.getView(), savedInstanceState);
assertThat(getLatestPopupWindow().isShowing()).isTrue();
} }
@Test @Test
@@ -221,8 +241,26 @@ public class AccessibilityShortcutPreferenceFragmentTest {
PreferredShortcuts.saveUserShortcutType(context, shortcut); PreferredShortcuts.saveUserShortcutType(context, shortcut);
} }
private static PopupWindow getLatestPopupWindow() {
final ShadowApplication shadowApplication =
Shadow.extract(ApplicationProvider.getApplicationContext());
return shadowApplication.getLatestPopupWindow();
}
public static class TestAccessibilityShortcutPreferenceFragment public static class TestAccessibilityShortcutPreferenceFragment
extends AccessibilityShortcutPreferenceFragment { extends AccessibilityShortcutPreferenceFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return mock(View.class);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// do nothing
}
@Override @Override
protected ComponentName getComponentName() { protected ComponentName getComponentName() {
return PLACEHOLDER_COMPONENT_NAME; return PLACEHOLDER_COMPONENT_NAME;
@@ -233,6 +271,16 @@ public class AccessibilityShortcutPreferenceFragmentTest {
return PLACEHOLDER_PACKAGE_NAME; return PLACEHOLDER_PACKAGE_NAME;
} }
@Override
protected ComponentName getTileComponentName() {
return PLACEHOLDER_TILE_COMPONENT_NAME;
}
@Override
protected CharSequence getTileName() {
return PLACEHOLDER_PACKAGE_NAME;
}
@Override @Override
public int getUserShortcutTypes() { public int getUserShortcutTypes() {
return 0; return 0;
@@ -263,5 +311,10 @@ public class AccessibilityShortcutPreferenceFragmentTest {
protected String getLogTag() { protected String getLogTag() {
return null; return null;
} }
@Override
public View getView() {
return mock(View.class);
}
}; };
} }