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

Commit 458eef30 authored by Roy Chou's avatar Roy Chou
Browse files

chore(#MagSettingsPanel): adjust SeekBarWithIconButtonsView callbacks

Originally, when clicking icon start/end on view, it would trigger seekbar.setProgress, then the seekbar will update position then trigger callback onProgressChanged with parameter fromUser false. This should be considered as user triggered action too. Therefore, we add new flag mSetProgressFromButtonFlag to help check if the progress changed is triggered by clicking icon button. If the flag is set, SeekBarWithIconButtonsViews would trigger onProgressChanged with parameter fromUser true. Beside, we extend OnSeekBarChangeListener to new interface OnSeekBarWithIconButtonsChangeListener and add method onUserInteractionFinalized in the interface. With the new method, outside listeners can distinguish whether the seekbar progress changed is trigger by dragging the slider or cliking the button.

Bug: 286176069
Test: manually
      atest SeekBarWithIconButtonsViewTest
      atest FontScalingDialogTest
      atest WindowMagnificationSettingsTest
Change-Id: Ibb579a543e5c9286ed88faba8eef5d67f5a902f1
parent 11b85acc
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -172,7 +172,8 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
        };
    }

    private class ZoomSeekbarChangeListener implements SeekBar.OnSeekBarChangeListener {
    private class ZoomSeekbarChangeListener implements
            SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            float scale = (progress / (float) mSeekBarMagnitude) + SCALE_MIN_VALUE;
@@ -197,6 +198,11 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
        public void onStopTrackingTouch(SeekBar seekBar) {
            // Do nothing
        }

        @Override
        public void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control) {
            // Do nothing
        }
    }

    private final AccessibilityDelegate mPanelDelegate = new AccessibilityDelegate() {
@@ -521,7 +527,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 0,
                UserHandle.USER_CURRENT);
        setScaleSeekbar(scale);
        mZoomSeekbar.setOnSeekBarChangeListener(new ZoomSeekbarChangeListener());
        mZoomSeekbar.setOnSeekBarWithIconButtonsChangeListener(new ZoomSeekbarChangeListener());

        mAllowDiagonalScrollingView =
                (LinearLayout) mSettingView.findViewById(R.id.magnifier_horizontal_lock_view);
+18 −13
Original line number Diff line number Diff line
@@ -26,12 +26,13 @@ import android.util.TypedValue
import android.view.LayoutInflater
import android.widget.Button
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import com.android.systemui.R
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener.ControlUnitType
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
@@ -105,30 +106,34 @@ class FontScalingDialog(
        lastProgress.set(fontSizeValueToIndex(currentScale))
        seekBarWithIconButtonsView.setProgress(lastProgress.get())

        seekBarWithIconButtonsView.setOnSeekBarChangeListener(
            object : OnSeekBarChangeListener {
                var isTrackingTouch = false

        seekBarWithIconButtonsView.setOnSeekBarWithIconButtonsChangeListener(
            object : OnSeekBarWithIconButtonsChangeListener {
                override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                    // Always provide preview configuration for text first when there is a change
                    // in the seekbar progress.
                    createTextPreview(progress)

                    if (!isTrackingTouch) {
                        // The seekbar progress is changed by icon buttons
                        changeFontSize(progress, CHANGE_BY_BUTTON_DELAY_MS)
                    }
                }

                override fun onStartTrackingTouch(seekBar: SeekBar) {
                    isTrackingTouch = true
                    // Do nothing
                }

                override fun onStopTrackingTouch(seekBar: SeekBar) {
                    isTrackingTouch = false
                    // Do nothing
                }

                override fun onUserInteractionFinalized(
                    seekBar: SeekBar,
                    @ControlUnitType control: Int
                ) {
                    if (control == ControlUnitType.BUTTON) {
                        // The seekbar progress is changed by icon buttons
                        changeFontSize(seekBar.progress, CHANGE_BY_BUTTON_DELAY_MS)
                    } else {
                        changeFontSize(seekBar.progress, CHANGE_BY_SEEKBAR_DELAY_MS)
                    }
                }
            }
        )
        doneButton.setOnClickListener { dismiss() }
        systemSettings.registerContentObserver(Settings.System.FONT_SCALE, fontSizeObserver)
+84 −22
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.common.ui.view;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
@@ -30,6 +31,9 @@ import android.widget.SeekBar;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * The layout contains a seekbar whose progress could be modified
 * through the icons on two ends of the seekbar.
@@ -47,6 +51,8 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
    private SeekBar mSeekbar;
    private int mSeekBarChangeMagnitude = 1;

    private boolean mSetProgressFromButtonFlag = false;

    private SeekBarChangeListener mSeekBarListener = new SeekBarChangeListener();
    private String[] mStateLabels = null;

@@ -121,21 +127,8 @@ public class SeekBarWithIconButtonsView extends LinearLayout {

        mSeekbar.setOnSeekBarChangeListener(mSeekBarListener);

        mIconStartFrame.setOnClickListener((view) -> {
            final int progress = mSeekbar.getProgress();
            if (progress > 0) {
                mSeekbar.setProgress(progress - mSeekBarChangeMagnitude);
                setIconViewAndFrameEnabled(mIconStart, mSeekbar.getProgress() > 0);
            }
        });

        mIconEndFrame.setOnClickListener((view) -> {
            final int progress = mSeekbar.getProgress();
            if (progress < mSeekbar.getMax()) {
                mSeekbar.setProgress(progress + mSeekBarChangeMagnitude);
                setIconViewAndFrameEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
            }
        });
        mIconStartFrame.setOnClickListener((view) -> onIconStartClicked());
        mIconEndFrame.setOnClickListener((view) -> onIconEndClicked());
    }

    private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
@@ -172,9 +165,9 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
     * Sets a onSeekbarChangeListener to the seekbar in the layout.
     * We update the Start Icon and End Icon if needed when the seekbar progress is changed.
     */
    public void setOnSeekBarChangeListener(
            @Nullable SeekBar.OnSeekBarChangeListener onSeekBarChangeListener) {
        mSeekBarListener.setOnSeekBarChangeListener(onSeekBarChangeListener);
    public void setOnSeekBarWithIconButtonsChangeListener(
            @Nullable OnSeekBarWithIconButtonsChangeListener onSeekBarChangeListener) {
        mSeekBarListener.setOnSeekBarWithIconButtonsChangeListener(onSeekBarChangeListener);
    }

    /**
@@ -216,16 +209,72 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
     */
    public void setProgress(int progress) {
        mSeekbar.setProgress(progress);
        updateIconViewIfNeeded(progress);
        updateIconViewIfNeeded(mSeekbar.getProgress());
    }

    private void setProgressFromButton(int progress) {
        mSetProgressFromButtonFlag = true;
        mSeekbar.setProgress(progress);
        updateIconViewIfNeeded(mSeekbar.getProgress());
    }

    private void onIconStartClicked() {
        final int progress = mSeekbar.getProgress();
        if (progress > 0) {
            setProgressFromButton(progress - mSeekBarChangeMagnitude);
        }
    }

    private void onIconEndClicked() {
        final int progress = mSeekbar.getProgress();
        if (progress < mSeekbar.getMax()) {
            setProgressFromButton(progress + mSeekBarChangeMagnitude);
        }
    }

    /**
     * Get current seekbar progress
     *
     * @return
     */
    @VisibleForTesting
    public int getProgress() {
        return mSeekbar.getProgress();
    }

    /**
     * Extended from {@link SeekBar.OnSeekBarChangeListener} to add callback to notify the listeners
     * the user interaction with the SeekBarWithIconButtonsView is finalized.
     */
    public interface OnSeekBarWithIconButtonsChangeListener
            extends SeekBar.OnSeekBarChangeListener {

        @Retention(RetentionPolicy.SOURCE)
        @IntDef({
                ControlUnitType.SLIDER,
                ControlUnitType.BUTTON
        })
        /** Denotes the Last user interacted control unit type. */
        @interface ControlUnitType {
            int SLIDER = 0;
            int BUTTON = 1;
        }

        /**
         * Notification that the user interaction with SeekBarWithIconButtonsView is finalized. This
         * would be triggered after user ends dragging on the slider or clicks icon buttons.
         *
         * @param seekBar The SeekBar in which the user ends interaction with
         * @param control The last user interacted control unit. It would be
         *                {@link ControlUnitType#SLIDER} if the user was changing the seekbar
         *                progress through dragging the slider, or {@link ControlUnitType#BUTTON}
         *                is the user was clicking button to change the progress.
         */
        void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control);
    }

    private class SeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
        private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = null;
        private OnSeekBarWithIconButtonsChangeListener mOnSeekBarChangeListener = null;

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -233,8 +282,18 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
                setSeekbarStateDescription();
            }
            if (mOnSeekBarChangeListener != null) {
                if (mSetProgressFromButtonFlag) {
                    mSetProgressFromButtonFlag = false;
                    mOnSeekBarChangeListener.onProgressChanged(
                            seekBar, progress, /* fromUser= */ true);
                    // Directly trigger onUserInteractionFinalized since the interaction
                    // (click button) is ended.
                    mOnSeekBarChangeListener.onUserInteractionFinalized(
                            seekBar, OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON);
                } else {
                    mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
                }
            }
            updateIconViewIfNeeded(progress);
        }

@@ -249,10 +308,13 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
        public void onStopTrackingTouch(SeekBar seekBar) {
            if (mOnSeekBarChangeListener != null) {
                mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
                mOnSeekBarChangeListener.onUserInteractionFinalized(
                        seekBar, OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
            }
        }

        void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
        void setOnSeekBarWithIconButtonsChangeListener(
                OnSeekBarWithIconButtonsChangeListener listener) {
            mOnSeekBarChangeListener = listener;
        }
    }
+18 −7
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.capture
@@ -67,7 +68,7 @@ class FontScalingDialogTest : SysuiTestCase() {

    @Mock private lateinit var userTracker: UserTracker
    @Captor
    private lateinit var seekBarChangeCaptor: ArgumentCaptor<SeekBar.OnSeekBarChangeListener>
    private lateinit var seekBarChangeCaptor: ArgumentCaptor<OnSeekBarWithIconButtonsChangeListener>

    @Before
    fun setUp() {
@@ -176,16 +177,17 @@ class FontScalingDialogTest : SysuiTestCase() {
    fun progressChanged_keyWasNotSetBefore_fontScalingHasBeenChangedIsOn() {
        fontScalingDialog.show()

        val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
            fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
        val iconStartFrame: ViewGroup = fontScalingDialog.findViewById(R.id.icon_start_frame)!!
        secureSettings.putIntForUser(
            Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
            OFF,
            userTracker.userId
        )

        // Default seekbar progress for font size is 1, set it to another progress 0
        seekBarWithIconButtonsView.setProgress(0)
        // Default seekbar progress for font size is 1, click start icon to decrease the progress
        iconStartFrame.performClick()
        backgroundDelayableExecutor.runAllReady()
        backgroundDelayableExecutor.advanceClockToNext()
        backgroundDelayableExecutor.runAllReady()

        val currentSettings =
@@ -208,7 +210,7 @@ class FontScalingDialogTest : SysuiTestCase() {
            )
            .thenReturn(slider)
        fontScalingDialog.show()
        verify(slider).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
        verify(slider).setOnSeekBarWithIconButtonsChangeListener(capture(seekBarChangeCaptor))
        val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!!

        // Default seekbar progress for font size is 1, simulate dragging to 0 without
@@ -237,6 +239,15 @@ class FontScalingDialogTest : SysuiTestCase() {
        backgroundDelayableExecutor.advanceClockToNext()
        backgroundDelayableExecutor.runAllReady()

        // SeekBar interaction is finalized.
        seekBarChangeCaptor.value.onUserInteractionFinalized(
            seekBar,
            OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER
        )
        backgroundDelayableExecutor.runAllReady()
        backgroundDelayableExecutor.advanceClockToNext()
        backgroundDelayableExecutor.runAllReady()

        // Verify that the scale of font size has been updated.
        systemScale =
            systemSettings.getFloatForUser(
@@ -258,7 +269,7 @@ class FontScalingDialogTest : SysuiTestCase() {
            )
            .thenReturn(slider)
        fontScalingDialog.show()
        verify(slider).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
        verify(slider).setOnSeekBarWithIconButtonsChangeListener(capture(seekBarChangeCaptor))
        val seekBar: SeekBar = slider.findViewById(R.id.seekbar)!!

        // Default seekbar progress for font size is 1, simulate dragging to 0 without
+63 −0
Original line number Diff line number Diff line
@@ -18,6 +18,13 @@ package com.android.systemui.common.ui.view;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;

import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ViewGroup;
@@ -28,10 +35,15 @@ import androidx.test.filters.SmallTest;

import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

/**
 * Tests for {@link SeekBarWithIconButtonsView}
@@ -48,14 +60,22 @@ public class SeekBarWithIconButtonsViewTest extends SysuiTestCase {
    private SeekBar mSeekbar;
    private SeekBarWithIconButtonsView mIconDiscreteSliderLinearLayout;

    @Mock
    private OnSeekBarWithIconButtonsChangeListener mOnSeekBarChangeListener;

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

        mIconDiscreteSliderLinearLayout = new SeekBarWithIconButtonsView(mContext);
        mIconStart = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_start);
        mIconEnd = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_end);
        mIconStartFrame = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_start_frame);
        mIconEndFrame = mIconDiscreteSliderLinearLayout.findViewById(R.id.icon_end_frame);
        mSeekbar = mIconDiscreteSliderLinearLayout.findViewById(R.id.seekbar);

        mIconDiscreteSliderLinearLayout.setOnSeekBarWithIconButtonsChangeListener(
                mOnSeekBarChangeListener);
    }

    @Test
@@ -108,6 +128,49 @@ public class SeekBarWithIconButtonsViewTest extends SysuiTestCase {
        assertThat(mSeekbar.getProgress()).isEqualTo(0);
    }

    @Test
    public void setProgress_onlyOnProgressChangedTriggeredWithFromUserFalse() {
        reset(mOnSeekBarChangeListener);
        mIconDiscreteSliderLinearLayout.setProgress(1);

        verify(mOnSeekBarChangeListener).onProgressChanged(
                eq(mSeekbar), /* progress= */ eq(1), /* fromUser= */ eq(false));
        verify(mOnSeekBarChangeListener, never()).onStartTrackingTouch(/* seekBar= */ any());
        verify(mOnSeekBarChangeListener, never()).onStopTrackingTouch(/* seekBar= */ any());
        verify(mOnSeekBarChangeListener, never()).onUserInteractionFinalized(
                /* seekBar= */any(), /* control= */ anyInt());
    }

    @Test
    public void clickIconEnd_triggerCallbacksInSequence() {
        final int magnitude = mIconDiscreteSliderLinearLayout.getChangeMagnitude();
        mIconDiscreteSliderLinearLayout.setProgress(0);
        reset(mOnSeekBarChangeListener);

        mIconEndFrame.performClick();

        InOrder inOrder = Mockito.inOrder(mOnSeekBarChangeListener);
        inOrder.verify(mOnSeekBarChangeListener).onProgressChanged(
                eq(mSeekbar), /* progress= */ eq(magnitude), /* fromUser= */ eq(true));
        inOrder.verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
                eq(mSeekbar), eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON));
    }

    @Test
    public void clickIconStart_triggerCallbacksInSequence() {
        final int magnitude = mIconDiscreteSliderLinearLayout.getChangeMagnitude();
        mIconDiscreteSliderLinearLayout.setProgress(magnitude);
        reset(mOnSeekBarChangeListener);

        mIconStartFrame.performClick();

        InOrder inOrder = Mockito.inOrder(mOnSeekBarChangeListener);
        inOrder.verify(mOnSeekBarChangeListener).onProgressChanged(
                eq(mSeekbar), /* progress= */ eq(0), /* fromUser= */ eq(true));
        inOrder.verify(mOnSeekBarChangeListener).onUserInteractionFinalized(
                eq(mSeekbar), eq(OnSeekBarWithIconButtonsChangeListener.ControlUnitType.BUTTON));
    }

    @Test
    public void setProgressStateLabels_getExpectedStateDescriptionOnInitialization() {
        String[] stateLabels = new String[]{"1", "2", "3", "4", "5"};