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

Commit d3bead82 authored by Wesley Wang's avatar Wesley Wang
Browse files

Export callback to receive seekbar change event from SeekBarPrefernce

  - Export onSeekBarChangeListener callback to receive change event from parent
  - Update battery saver schedule trigger threshold after seekbar tounch
    ending instead of update it every time during dragging or touching

Bug: 236356020
Test: make RunSettingsRoboTests
Change-Id: Ifee7cd9e7cabfbec0817a4c28254228f885d6a8d
parent 315c78b8
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.Context;
import android.os.PowerManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
@@ -42,22 +44,27 @@ import com.android.settings.widget.SeekBarPreference;
 * See {@link Settings.Global#AUTOMATIC_POWER_SAVE_MODE} for more details.
 */
public class BatterySaverScheduleSeekBarController implements
        OnPreferenceChangeListener {
        OnPreferenceChangeListener, OnSeekBarChangeListener {

    public static final int MAX_SEEKBAR_VALUE = 15;
    public static final int MIN_SEEKBAR_VALUE = 2;
    public static final String KEY_BATTERY_SAVER_SEEK_BAR = "battery_saver_seek_bar";
    private static final int LEVEL_UNIT_SCALE = 5;

    @VisibleForTesting
    public SeekBarPreference mSeekBarPreference;
    private Context mContext;

    @VisibleForTesting
    int mPercentage;

    public BatterySaverScheduleSeekBarController(Context context) {
        mContext = context;
        mSeekBarPreference = new SeekBarPreference(context);
        mSeekBarPreference.setLayoutResource(R.layout.preference_widget_seekbar_settings);
        mSeekBarPreference.setIconSpaceReserved(false);
        mSeekBarPreference.setOnPreferenceChangeListener(this);
        mSeekBarPreference.setOnSeekBarChangeListener(this);
        mSeekBarPreference.setContinuousUpdates(true);
        mSeekBarPreference.setMax(MAX_SEEKBAR_VALUE);
        mSeekBarPreference.setMin(MIN_SEEKBAR_VALUE);
@@ -68,16 +75,28 @@ public class BatterySaverScheduleSeekBarController implements

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        // The nits are in intervals of 5%
        final int percentage = ((Integer) newValue) * 5;
        Settings.Global.putInt(mContext.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL,
                percentage);
        final CharSequence stateDescription = formatStateDescription(percentage);
        mPercentage = ((Integer) newValue) * LEVEL_UNIT_SCALE;
        final CharSequence stateDescription = formatStateDescription(mPercentage);
        preference.setTitle(stateDescription);
        mSeekBarPreference.overrideSeekBarStateDescription(stateDescription);
        return true;
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {}

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        if (mPercentage > 0) {
            Settings.Global.putInt(mContext.getContentResolver(),
                    Global.LOW_POWER_MODE_TRIGGER_LEVEL,
                    mPercentage);
        }
    }

    public void updateSeekBar() {
        final ContentResolver resolver = mContext.getContentResolver();
        // Note: this can also be obtained via PowerManager.getPowerSaveModeTrigger()
+18 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ public class SeekBarPreference extends RestrictedPreference
    private CharSequence mOverrideSeekBarStateDescription;
    private CharSequence mSeekBarContentDescription;
    private CharSequence mSeekBarStateDescription;
    private OnSeekBarChangeListener mOnSeekBarChangeListener;

    public SeekBarPreference(
            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
@@ -101,6 +102,14 @@ public class SeekBarPreference extends RestrictedPreference
        this(context, null);
    }

    /**
     * A callback that notifies clients when the seekbar progress level has been
     * changed. See {@link OnSeekBarChangeListener} for more info.
     */
    public void setOnSeekBarChangeListener(OnSeekBarChangeListener listener) {
        mOnSeekBarChangeListener = listener;
    }

    public void setShouldBlink(boolean shouldBlink) {
        mShouldBlink = shouldBlink;
        notifyChanged();
@@ -301,6 +310,9 @@ public class SeekBarPreference extends RestrictedPreference
        if (fromUser && (mContinuousUpdates || !mTrackingTouch)) {
            syncProgress(seekBar);
        }
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
        }
    }

    @Override
@@ -309,6 +321,9 @@ public class SeekBarPreference extends RestrictedPreference
        mJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
                .withView(CUJ_SETTINGS_SLIDER, seekBar)
                .setTag(getKey()));
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onStartTrackingTouch(seekBar);
        }
    }

    @Override
@@ -317,6 +332,9 @@ public class SeekBarPreference extends RestrictedPreference
        if (seekBar.getProgress() != mProgress) {
            syncProgress(seekBar);
        }
        if (mOnSeekBarChangeListener != null) {
            mOnSeekBarChangeListener.onStopTrackingTouch(seekBar);
        }
        mJankMonitor.end(CUJ_SETTINGS_SLIDER);
    }

+45 −7
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ import android.content.Context;
import android.os.PowerManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.widget.SeekBar;

import androidx.preference.PreferenceScreen;

@@ -46,22 +47,47 @@ public class BatterySaverScheduleSeekBarControllerTest {
    }

    @Test
    public void onPreferenceChange_updatesSettingsGlobal() {
    public void onPreferenceChange_withoutOnStopTrackingTouch_updatesTitleAndDescriptionOnly() {
        final CharSequence expectedTitle = "50%";
        Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 5);
        setTriggerLevel(5);

        mController.onPreferenceChange(mController.mSeekBarPreference, 10);
        assertThat(Settings.Global.getInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1))
                .isEqualTo(50);

        assertThat(getTriggerLevel()).isEqualTo(5);
        assertThat(mController.mSeekBarPreference.getTitle()).isEqualTo(expectedTitle);
        verify(mController.mSeekBarPreference).overrideSeekBarStateDescription(expectedTitle);
    }

    @Test
    public void onPreferenceChange_withOnStopTrackingTouch_updatesSettingsGlobal() {
        final CharSequence expectedTitle = "50%";
        setTriggerLevel(5);

        mController.onPreferenceChange(mController.mSeekBarPreference, 10);
        mController.onStopTrackingTouch(new SeekBar(mContext));

        assertThat(getTriggerLevel()).isEqualTo(50);
        assertThat(mController.mSeekBarPreference.getTitle()).isEqualTo(expectedTitle);
        verify(mController.mSeekBarPreference).overrideSeekBarStateDescription(expectedTitle);
    }

    @Test
    public void onStopTrackingTouch_invalidValue_noUpdates() {
        setTriggerLevel(5);

        mController.mPercentage = 0;
        mController.onStopTrackingTouch(new SeekBar(mContext));

        assertThat(getTriggerLevel()).isEqualTo(5);
    }

    @Test
    public void updateSeekBar_routineMode_hasCorrectProperties() {
        Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVE_MODE,
                PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC);

        mController.updateSeekBar();

        assertThat(mController.mSeekBarPreference.isVisible()).isFalse();
        verify(mController.mSeekBarPreference, never()).overrideSeekBarStateDescription(any());
    }
@@ -71,7 +97,8 @@ public class BatterySaverScheduleSeekBarControllerTest {
        final CharSequence expectedTitle = "10%";
        Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVE_MODE,
                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
        Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 10);
        setTriggerLevel(10);

        mController.updateSeekBar();

        assertThat(mController.mSeekBarPreference.isVisible()).isTrue();
@@ -83,8 +110,10 @@ public class BatterySaverScheduleSeekBarControllerTest {
    public void updateSeekBar_noneMode_hasCorrectProperties() {
        Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVE_MODE,
                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
        Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
        setTriggerLevel(0);

        mController.updateSeekBar();

        assertThat(mController.mSeekBarPreference.isVisible()).isFalse();
        verify(mController.mSeekBarPreference, never()).overrideSeekBarStateDescription(any());
    }
@@ -93,9 +122,18 @@ public class BatterySaverScheduleSeekBarControllerTest {
    public void addToScreen_addsToEnd() {
        Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVE_MODE,
                PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
        Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15);
        setTriggerLevel(15);

        mController.addToScreen(mScreen);

        assertThat(mController.mSeekBarPreference.getOrder()).isEqualTo(100);
    }

    private void setTriggerLevel(int level) {
        Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, level);
    }

    private int getTriggerLevel() {
        return Settings.Global.getInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1);
    }
}
+53 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;

@@ -40,6 +41,7 @@ import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -59,6 +61,9 @@ public class SeekBarPreferenceTest {
    private SeekBarPreference mSeekBarPreference;
    private SeekBar mSeekBar;

    @Mock
    SeekBar.OnSeekBarChangeListener mMockOnSeekBarChangeListener;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -179,6 +184,54 @@ public class SeekBarPreferenceTest {
        assertThat(shadowOf(mSeekBar).lastHapticFeedbackPerformed()).isEqualTo(CLOCK_TICK);
    }

    @Test
    public void onProgressChanged_hasSeekBarChangeListener_receiveCallBack() {
        mSeekBarPreference.setOnSeekBarChangeListener(mMockOnSeekBarChangeListener);

        mSeekBarPreference.onProgressChanged(mSeekBar, PROGRESS, true);

        verify(mMockOnSeekBarChangeListener).onProgressChanged(mSeekBar, PROGRESS, true);
    }

    @Test
    public void onProgressChanged_noSeekBarChangeListener_noAction() {
        mSeekBarPreference.onProgressChanged(mSeekBar, PROGRESS, true);

        verifyZeroInteractions(mMockOnSeekBarChangeListener);
    }

    @Test
    public void onStartTrackingTouch_hasSeekBarChangeListener_receiveCallBack() {
        mSeekBarPreference.setOnSeekBarChangeListener(mMockOnSeekBarChangeListener);

        mSeekBarPreference.onStartTrackingTouch(mSeekBar);

        verify(mMockOnSeekBarChangeListener).onStartTrackingTouch(mSeekBar);
    }

    @Test
    public void onStartTrackingTouch_noSeekBarChangeListener_noAction() {
        mSeekBarPreference.onStartTrackingTouch(mSeekBar);

        verifyZeroInteractions(mMockOnSeekBarChangeListener);
    }

    @Test
    public void onStopTrackingTouch_hasSeekBarChangeListener_receiveCallBack() {
        mSeekBarPreference.setOnSeekBarChangeListener(mMockOnSeekBarChangeListener);

        mSeekBarPreference.onStopTrackingTouch(mSeekBar);

        verify(mMockOnSeekBarChangeListener).onStopTrackingTouch(mSeekBar);
    }

    @Test
    public void onStopTrackingTouch_noSeekBarChangeListener_noAction() {
        mSeekBarPreference.onStopTrackingTouch(mSeekBar);

        verifyZeroInteractions(mMockOnSeekBarChangeListener);
    }

    public static class TestFragment extends PreferenceFragmentCompat {
        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {