Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b132ada1 authored by Candice Lo's avatar Candice Lo
Browse files

Create tooltip for notifying auto-adding the font scaling tile

1. Add string for the content of tooltip.
2. Show the tooltip if needed: the tooltip will only be shown once when users change the font size from the Settings page for the first time.
3. Since the layout shown on the screen will be recreated after font size changes, we need to save the state of the tooltip popup window to check if we need to reshow it in displayPreference.

Bug: 269679768
Test: Manually - attach videos to the bug
Test: make RunSettingsRoboTests ROBOTEST_FILTER=PreviewSizeSeekBarControllerTest
Change-Id: I1b6c5fdbd74c7a868cf42bd21d2cdb1052c0bbe6
parent 813f654a
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -4567,6 +4567,8 @@
    <string name="accessibility_one_handed_mode_auto_added_qs_tooltip_content">One-handed mode added to Quick Settings. Swipe down to turn it on or off anytime.</string>
    <string name="accessibility_one_handed_mode_auto_added_qs_tooltip_content">One-handed mode added to Quick Settings. Swipe down to turn it on or off anytime.</string>
    <!-- Used in the One-hand mode settings to show quick settings tooltip. [CHAR LIMIT=NONE] -->
    <!-- Used in the One-hand mode settings to show quick settings tooltip. [CHAR LIMIT=NONE] -->
    <string name="accessibility_one_handed_mode_qs_tooltip_content">You can also add one-handed mode to Quick Settings from the top of your screen</string>
    <string name="accessibility_one_handed_mode_qs_tooltip_content">You can also add one-handed mode to Quick Settings from the top of your screen</string>
    <!-- Used in the font size settings to show quick settings tooltip for auto-added feature. [CHAR LIMIT=NONE] -->
    <string name="accessibility_font_scaling_auto_added_qs_tooltip_content">Font size added to Quick Settings. Swipe down to change the font size anytime.</string>
    <!-- Used in the accessibility action for accessibility quick settings tooltip to dismiss. [CHAR LIMIT=NONE] -->
    <!-- Used in the accessibility action for accessibility quick settings tooltip to dismiss. [CHAR LIMIT=NONE] -->
    <string name="accessibility_quick_settings_tooltip_dismiss">Dismiss</string>
    <string name="accessibility_quick_settings_tooltip_dismiss">Dismiss</string>
    <!-- Used in the Color correction settings screen to control turning on/off the feature entirely [CHAR LIMIT=60] -->
    <!-- Used in the Color correction settings screen to control turning on/off the feature entirely [CHAR LIMIT=60] -->
+85 −2
Original line number Original line Diff line number Diff line
@@ -16,14 +16,22 @@


package com.android.settings.accessibility;
package com.android.settings.accessibility;


import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.widget.SeekBar;
import android.widget.SeekBar;


import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceScreen;


import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.widget.LabeledSeekBarPreference;
import com.android.settings.widget.LabeledSeekBarPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;


import java.util.Optional;
import java.util.Optional;


@@ -31,12 +39,19 @@ import java.util.Optional;
 * The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
 * The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
 * settings changes and updates preview size threshold smoothly.
 * settings changes and updates preview size threshold smoothly.
 */
 */
class PreviewSizeSeekBarController extends BasePreferenceController implements
abstract class PreviewSizeSeekBarController extends BasePreferenceController implements
        TextReadingResetController.ResetStateListener {
        TextReadingResetController.ResetStateListener, LifecycleObserver, OnCreate,
        OnDestroy, OnSaveInstanceState {
    private final PreviewSizeData<? extends Number> mSizeData;
    private final PreviewSizeData<? extends Number> mSizeData;
    private static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
    private boolean mSeekByTouch;
    private boolean mSeekByTouch;
    private Optional<ProgressInteractionListener> mInteractionListener = Optional.empty();
    private Optional<ProgressInteractionListener> mInteractionListener = Optional.empty();
    private LabeledSeekBarPreference mSeekBarPreference;
    private LabeledSeekBarPreference mSeekBarPreference;
    private int mLastProgress;
    private boolean mNeedsQSTooltipReshow = false;
    private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
    private final Handler mHandler;



    private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
    private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
            new SeekBar.OnSeekBarChangeListener() {
            new SeekBar.OnSeekBarChangeListener() {
@@ -54,6 +69,7 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements


                    if (!mSeekByTouch) {
                    if (!mSeekByTouch) {
                        interactionListener.onProgressChanged();
                        interactionListener.onProgressChanged();
                        onProgressFinalized();
                    }
                    }
                }
                }


@@ -67,6 +83,7 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
                    mSeekByTouch = false;
                    mSeekByTouch = false;


                    mInteractionListener.ifPresent(ProgressInteractionListener::onEndTrackingTouch);
                    mInteractionListener.ifPresent(ProgressInteractionListener::onEndTrackingTouch);
                    onProgressFinalized();
                }
                }
            };
            };


@@ -74,6 +91,30 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
            @NonNull PreviewSizeData<? extends Number> sizeData) {
            @NonNull PreviewSizeData<? extends Number> sizeData) {
        super(context, preferenceKey);
        super(context, preferenceKey);
        mSizeData = sizeData;
        mSizeData = sizeData;
        mHandler = new Handler(context.getMainLooper());
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Restore the tooltip.
        if (savedInstanceState != null
                && savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_RESHOW)) {
            mNeedsQSTooltipReshow = savedInstanceState.getBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW);
        }
    }

    @Override
    public void onDestroy() {
        // remove runnables in the queue.
        mHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        final boolean isTooltipWindowShowing = mTooltipWindow != null && mTooltipWindow.isShowing();
        if (mNeedsQSTooltipReshow || isTooltipWindowShowing) {
            outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
        }
    }
    }


    void setInteractionListener(ProgressInteractionListener interactionListener) {
    void setInteractionListener(ProgressInteractionListener interactionListener) {
@@ -91,11 +132,15 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements


        final int dataSize = mSizeData.getValues().size();
        final int dataSize = mSizeData.getValues().size();
        final int initialIndex = mSizeData.getInitialIndex();
        final int initialIndex = mSizeData.getInitialIndex();
        mLastProgress = initialIndex;
        mSeekBarPreference = screen.findPreference(getPreferenceKey());
        mSeekBarPreference = screen.findPreference(getPreferenceKey());
        mSeekBarPreference.setMax(dataSize - 1);
        mSeekBarPreference.setMax(dataSize - 1);
        mSeekBarPreference.setProgress(initialIndex);
        mSeekBarPreference.setProgress(initialIndex);
        mSeekBarPreference.setContinuousUpdates(true);
        mSeekBarPreference.setContinuousUpdates(true);
        mSeekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener);
        mSeekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener);
        if (mNeedsQSTooltipReshow) {
            mHandler.post(this::showQuickSettingsTooltipIfNeeded);
        }
    }
    }


    @Override
    @Override
@@ -108,6 +153,44 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
        mInteractionListener.ifPresent(ProgressInteractionListener::onProgressChanged);
        mInteractionListener.ifPresent(ProgressInteractionListener::onProgressChanged);
    }
    }


    private void onProgressFinalized() {
        // Using progress in SeekBarPreference since the progresses in
        // SeekBarPreference and seekbar are not always the same.
        // See {@link androidx.preference.Preference#callChangeListener(Object)}
        int seekBarPreferenceProgress = mSeekBarPreference.getProgress();
        if (seekBarPreferenceProgress != mLastProgress) {
            showQuickSettingsTooltipIfNeeded();
            mLastProgress = seekBarPreferenceProgress;
        }
    }

    private void showQuickSettingsTooltipIfNeeded() {
        final ComponentName tileComponentName = getTileComponentName();
        if (tileComponentName == null) {
            // Returns if no tile service assigned.
            return;
        }

        if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
                mContext, tileComponentName)) {
            // Returns if quick settings tooltip only show once.
            return;
        }

        mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(mContext);
        mTooltipWindow.setup(getTileTooltipContent(),
                R.drawable.accessibility_auto_added_qs_tooltip_illustration);
        mTooltipWindow.showAtTopCenter(mSeekBarPreference.getSeekbar());
        AccessibilityQuickSettingUtils.optInValueToSharedPreferences(mContext, tileComponentName);
        mNeedsQSTooltipReshow = false;
    }

    /** Returns the accessibility Quick Settings tile component name. */
    abstract ComponentName getTileComponentName();

    /** Returns accessibility Quick Settings tile tooltip content. */
    abstract CharSequence getTileTooltipContent();



    /**
    /**
     * Interface for callbacks when users interact with the seek bar.
     * Interface for callbacks when users interact with the seek bar.
+26 −2
Original line number Original line Diff line number Diff line
@@ -16,11 +16,13 @@


package com.android.settings.accessibility;
package com.android.settings.accessibility;


import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_COMPONENT_NAME;
import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;


import android.app.Activity;
import android.app.Activity;
import android.app.Dialog;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Bundle;
@@ -156,12 +158,34 @@ public class TextReadingPreferenceFragment extends DashboardFragment {
        controllers.add(mPreviewController);
        controllers.add(mPreviewController);


        final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
        final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
                context, FONT_SIZE_KEY, fontSizeData);
                context, FONT_SIZE_KEY, fontSizeData) {
            @Override
            ComponentName getTileComponentName() {
                return FONT_SIZE_COMPONENT_NAME;
            }

            @Override
            CharSequence getTileTooltipContent() {
                return context.getText(
                        R.string.accessibility_font_scaling_auto_added_qs_tooltip_content);
            }
        };
        fontSizeController.setInteractionListener(mPreviewController);
        fontSizeController.setInteractionListener(mPreviewController);
        getSettingsLifecycle().addObserver(fontSizeController);
        controllers.add(fontSizeController);
        controllers.add(fontSizeController);


        final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
        final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
                context, DISPLAY_SIZE_KEY, displaySizeData);
                context, DISPLAY_SIZE_KEY, displaySizeData) {
            @Override
            ComponentName getTileComponentName() {
                return null;
            }

            @Override
            CharSequence getTileTooltipContent() {
                return null;
            }
        };
        displaySizeController.setInteractionListener(mPreviewController);
        displaySizeController.setInteractionListener(mPreviewController);
        controllers.add(displaySizeController);
        controllers.add(displaySizeController);


+10 −4
Original line number Original line Diff line number Diff line
@@ -63,6 +63,8 @@ public class LabeledSeekBarPreference extends SeekBarPreference {
    private OnPreferenceChangeListener mStopListener;
    private OnPreferenceChangeListener mStopListener;
    private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener;
    private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener;


    private SeekBar mSeekBar;

    public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
    public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
            int defStyleRes) {


@@ -104,6 +106,10 @@ public class LabeledSeekBarPreference extends SeekBarPreference {
                com.android.internal.R.attr.seekBarPreferenceStyle), 0);
                com.android.internal.R.attr.seekBarPreferenceStyle), 0);
    }
    }


    public SeekBar getSeekbar() {
        return mSeekBar;
    }

    @Override
    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);
        super.onBindViewHolder(holder);
@@ -133,19 +139,19 @@ public class LabeledSeekBarPreference extends SeekBarPreference {
        final boolean isValidTextResIdExist = mTextStartId > 0 || mTextEndId > 0;
        final boolean isValidTextResIdExist = mTextStartId > 0 || mTextEndId > 0;
        labelFrame.setVisibility(isValidTextResIdExist ? View.VISIBLE : View.GONE);
        labelFrame.setVisibility(isValidTextResIdExist ? View.VISIBLE : View.GONE);


        final SeekBar seekBar = (SeekBar) holder.findViewById(com.android.internal.R.id.seekbar);
        mSeekBar = (SeekBar) holder.findViewById(com.android.internal.R.id.seekbar);
        if (mTickMarkId != 0) {
        if (mTickMarkId != 0) {
            final Drawable tickMark = getContext().getDrawable(mTickMarkId);
            final Drawable tickMark = getContext().getDrawable(mTickMarkId);
            seekBar.setTickMark(tickMark);
            mSeekBar.setTickMark(tickMark);
        }
        }


        final ViewGroup iconStartFrame = (ViewGroup) holder.findViewById(R.id.icon_start_frame);
        final ViewGroup iconStartFrame = (ViewGroup) holder.findViewById(R.id.icon_start_frame);
        final ImageView iconStartView = (ImageView) holder.findViewById(R.id.icon_start);
        final ImageView iconStartView = (ImageView) holder.findViewById(R.id.icon_start);
        updateIconStartIfNeeded(iconStartFrame, iconStartView, seekBar);
        updateIconStartIfNeeded(iconStartFrame, iconStartView, mSeekBar);


        final ViewGroup iconEndFrame = (ViewGroup) holder.findViewById(R.id.icon_end_frame);
        final ViewGroup iconEndFrame = (ViewGroup) holder.findViewById(R.id.icon_end_frame);
        final ImageView iconEndView = (ImageView) holder.findViewById(R.id.icon_end);
        final ImageView iconEndView = (ImageView) holder.findViewById(R.id.icon_end);
        updateIconEndIfNeeded(iconEndFrame, iconEndView, seekBar);
        updateIconEndIfNeeded(iconEndFrame, iconEndView, mSeekBar);
    }
    }


    public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
    public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
+118 −5
Original line number Original line Diff line number Diff line
@@ -16,29 +16,45 @@


package com.android.settings.accessibility;
package com.android.settings.accessibility;


import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_COMPONENT_NAME;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;


import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
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;


import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.PopupWindow;
import android.widget.SeekBar;
import android.widget.SeekBar;


import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.core.app.ApplicationProvider;


import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
import com.android.settings.widget.LabeledSeekBarPreference;
import com.android.settings.widget.LabeledSeekBarPreference;


import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
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 PreviewSizeSeekBarController}.
 * Tests for {@link PreviewSizeSeekBarController}.
@@ -47,30 +63,67 @@ import org.robolectric.annotation.Config;
@Config(shadows = {ShadowInteractionJankMonitor.class})
@Config(shadows = {ShadowInteractionJankMonitor.class})
public class PreviewSizeSeekBarControllerTest {
public class PreviewSizeSeekBarControllerTest {
    private static final String FONT_SIZE_KEY = "font_size";
    private static final String FONT_SIZE_KEY = "font_size";
    private static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
    @Spy
    private final Context mContext = ApplicationProvider.getApplicationContext();
    private final Context mContext = ApplicationProvider.getApplicationContext();
    private PreviewSizeSeekBarController mSeekBarController;
    private PreviewSizeSeekBarController mSeekBarController;
    private FontSizeData mFontSizeData;
    private FontSizeData mFontSizeData;
    private LabeledSeekBarPreference mSeekBarPreference;
    private LabeledSeekBarPreference mSeekBarPreference;


    @Mock
    private PreferenceScreen mPreferenceScreen;
    private PreferenceScreen mPreferenceScreen;
    private TestFragment mFragment;
    private PreferenceViewHolder mHolder;
    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private PreferenceManager mPreferenceManager;


    @Mock
    @Mock
    private PreviewSizeSeekBarController.ProgressInteractionListener mInteractionListener;
    private PreviewSizeSeekBarController.ProgressInteractionListener mInteractionListener;


    private static PopupWindow getLatestPopupWindow() {
        final ShadowApplication shadowApplication =
                Shadow.extract(ApplicationProvider.getApplicationContext());
        return shadowApplication.getLatestPopupWindow();
    }

    @Before
    @Before
    public void setUp() {
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);


        mFontSizeData = new FontSizeData(mContext);
        mContext.setTheme(R.style.Theme_AppCompat);
        mFragment = spy(new TestFragment());
        when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
        when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
        when(mFragment.getContext()).thenReturn(mContext);
        mPreferenceScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
        when(mPreferenceScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
        doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen();
        mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null));
        mSeekBarPreference.setKey(FONT_SIZE_KEY);


        mSeekBarController =
        LayoutInflater inflater = LayoutInflater.from(mContext);
                new PreviewSizeSeekBarController(mContext, FONT_SIZE_KEY, mFontSizeData);
        mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
                R.layout.preference_labeled_slider, null));
        mSeekBarPreference.onBindViewHolder(mHolder);


        mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null));
        when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference);
        when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference);


        mFontSizeData = new FontSizeData(mContext);
        mSeekBarController =
                new PreviewSizeSeekBarController(mContext, FONT_SIZE_KEY, mFontSizeData) {
                    @Override
                    ComponentName getTileComponentName() {
                        return FONT_SIZE_COMPONENT_NAME;
                    }

                    @Override
                    CharSequence getTileTooltipContent() {
                        return mContext.getText(
                                R.string.accessibility_font_scaling_auto_added_qs_tooltip_content);
                    }
                };
        mSeekBarController.setInteractionListener(mInteractionListener);
        mSeekBarController.setInteractionListener(mInteractionListener);
        when(mPreferenceScreen.findPreference(mSeekBarController.getPreferenceKey())).thenReturn(
                mSeekBarPreference);
    }
    }


    @Test
    @Test
@@ -123,4 +176,64 @@ public class PreviewSizeSeekBarControllerTest {


        verify(mInteractionListener).notifyPreferenceChanged();
        verify(mInteractionListener).notifyPreferenceChanged();
    }
    }

    @Test
    public void onProgressChanged_showTooltipView() {
        mSeekBarController.displayPreference(mPreferenceScreen);

        // Simulate changing the progress for the first time
        int newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
        mSeekBarPreference.setProgress(newProgress);
        mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
                newProgress,
                /* fromUser= */ false);

        assertThat(getLatestPopupWindow().isShowing()).isTrue();
    }

    @Test
    public void onProgressChanged_tooltipViewHasBeenShown_notShowTooltipView() {
        mSeekBarController.displayPreference(mPreferenceScreen);
        // Simulate changing the progress for the first time
        int newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
        mSeekBarPreference.setProgress(newProgress);
        mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
                newProgress,
                /* fromUser= */ false);
        getLatestPopupWindow().dismiss();

        // Simulate progress changing for the second time
        newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
        mSeekBarPreference.setProgress(newProgress);
        mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
                newProgress,
                /* fromUser= */ false);

        assertThat(getLatestPopupWindow().isShowing()).isFalse();
    }

    @Test
    @Config(shadows = ShadowFragment.class)
    public void restoreValueFromSavedInstanceState_showTooltipView() {
        final Bundle savedInstanceState = new Bundle();
        savedInstanceState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
        mSeekBarController.onCreate(savedInstanceState);

        mSeekBarController.displayPreference(mPreferenceScreen);

        assertThat(getLatestPopupWindow().isShowing()).isTrue();
    }

    private static class TestFragment extends SettingsPreferenceFragment {

        @Override
        protected boolean shouldSkipForInitialSUW() {
            return false;
        }

        @Override
        public int getMetricsCategory() {
            return 0;
        }
    }
}
}