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

Commit 99117069 authored by Ebru Kurnaz's avatar Ebru Kurnaz
Browse files

Update Size preference if the resolution has changed.

Flag: com.android.settings.flags.display_size_connected_display_setting
Test: atest ExternalDisplayPreferenceFragmentTest
Bug: 399357095
Change-Id: I9e84c4958ffe7d679caabe28987b6ffffccbfc85
parent d82f6583
Loading
Loading
Loading
Loading
+9 −79
Original line number Diff line number Diff line
@@ -29,10 +29,7 @@ import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Choreographer;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.window.DesktopExperienceFlags;

@@ -46,13 +43,10 @@ import androidx.preference.PreferenceGroup;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragmentBase;
import com.android.settings.accessibility.AccessibilitySeekBarPreference;
import com.android.settings.accessibility.DisplaySizeData;
import com.android.settings.accessibility.TextReadingPreferenceFragment;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.Injector;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.display.DisplayDensityUtils;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.MainSwitchPreference;
@@ -352,38 +346,22 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
    }

    @NonNull
    private AccessibilitySeekBarPreference reuseSizePreference(Context context,
            PrefRefresh refresh, int displayId, int position) {
        AccessibilitySeekBarPreference pref =
    private ExternalDisplaySizePreference reuseSizePreference(Context context,
            PrefRefresh refresh, DisplayDevice display, int position) {
        ExternalDisplaySizePreference pref =
                refresh.findUnusedPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(position));
        if (pref == null) {
            pref = new AccessibilitySeekBarPreference(context, /* attrs= */ null);
            pref.setIconStart(R.drawable.ic_remove_24dp);
            pref.setIconStartContentDescription(R.string.screen_zoom_make_smaller_desc);
            pref.setIconEnd(R.drawable.ic_add_24dp);
            pref.setIconEndContentDescription(R.string.screen_zoom_make_larger_desc);
            pref = new ExternalDisplaySizePreference(context, /* attrs= */ null);
            PrefBasics.EXTERNAL_DISPLAY_SIZE.apply(pref, position);

            setStateForDisplaySizePreference(context, displayId, pref);
        }
        if (display.getMode() != null) {
            pref.setStateForPreference(display.getMode().getPhysicalWidth(),
                    display.getMode().getPhysicalHeight(), display.getId());
        }
        refresh.addPreference(pref);
        return pref;
    }

    private void setStateForDisplaySizePreference(Context context, int displayId,
            AccessibilitySeekBarPreference preference) {
        var displaySizeData = new DisplaySizeData(context,
                new DisplayDensityUtils(context, (info) -> info.displayId == displayId));
        ExternalDisplaySizePreferenceStateHandler seekBarChangeHandler =
                new ExternalDisplaySizePreferenceStateHandler(
                        displaySizeData, preference);

        preference.setMax(displaySizeData.getValues().size() - 1);
        preference.setProgress(displaySizeData.getInitialIndex());
        preference.setContinuousUpdates(false);
        preference.setOnSeekBarChangeListener(seekBarChangeHandler);
    }

    private void update() {
        final var screen = getPreferenceScreen();
        if (screen == null || mInjector == null || mInjector.getContext() == null) {
@@ -587,7 +565,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen

    private void addSizePreference(final Context context, PrefRefresh refresh,
            DisplayDevice display, int position) {
        var pref = reuseSizePreference(context, refresh, display.getId(), position);
        var pref = reuseSizePreference(context, refresh, display, position);
        pref.setSummary(EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE);
        pref.setOnPreferenceClickListener(
                (Preference p) -> {
@@ -637,54 +615,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
        }
    }

    private static class ExternalDisplaySizePreferenceStateHandler
            implements SeekBar.OnSeekBarChangeListener {
        private static final long MIN_COMMIT_INTERVAL_MS = 800;
        private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
        private final DisplaySizeData mDisplaySizeData;
        private int mLastDisplayProgress;
        private long mLastCommitTime;
        private final AccessibilitySeekBarPreference mPreference;
        ExternalDisplaySizePreferenceStateHandler(DisplaySizeData displaySizeData,
                AccessibilitySeekBarPreference preference) {
            mDisplaySizeData = displaySizeData;
            mPreference = preference;
        }

        final Choreographer.FrameCallback mCommit = this::tryCommitDisplaySizeConfig;

        private void tryCommitDisplaySizeConfig(long unusedFrameTimeNanos) {
            final int displayProgress = mPreference.getProgress();
            if (displayProgress != mLastDisplayProgress) {
                mDisplaySizeData.commit(displayProgress);
                mLastDisplayProgress = displayProgress;
            }
            mLastCommitTime = SystemClock.elapsedRealtime();
        }

        private void postCommitDelayed() {
            var commitDelayMs = CHANGE_BY_BUTTON_DELAY_MS;
            if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
                commitDelayMs += MIN_COMMIT_INTERVAL_MS;
            }

            final Choreographer choreographer = Choreographer.getInstance();
            choreographer.removeFrameCallback(mCommit);
            choreographer.postFrameCallbackDelayed(mCommit, commitDelayMs);
        }

        @Override
        public void onProgressChanged(@NonNull SeekBar seekBar, int i, boolean b) {
            postCommitDelayed();
        }

        @Override
        public void onStartTrackingTouch(@NonNull SeekBar seekBar) {}

        @Override
        public void onStopTrackingTouch(@NonNull SeekBar seekBar) {}
    }

    private static class PrefRefresh implements AutoCloseable {
        private final PreferenceGroup mScreen;
        private final HashMap<String, Preference> mUnusedPreferences = new HashMap<>();
+124 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.connecteddevice.display;

import android.content.Context;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.Choreographer;
import android.widget.SeekBar;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.settings.R;
import com.android.settings.accessibility.AccessibilitySeekBarPreference;
import com.android.settings.accessibility.DisplaySizeData;
import com.android.settingslib.display.DisplayDensityUtils;

/**
 * The display size preference setting used for External displays.
 */
public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreference {
    private int mDisplayWidth;
    private int mDisplayHeight;
    private int mDisplayId;
    private Context mContext;

    public ExternalDisplaySizePreference(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mDisplayId = -1;
        mDisplayWidth = 0;
        mDisplayHeight = 0;

        setIconStart(R.drawable.ic_remove_24dp);
        setIconStartContentDescription(R.string.screen_zoom_make_smaller_desc);
        setIconEnd(R.drawable.ic_add_24dp);
        setIconEndContentDescription(R.string.screen_zoom_make_larger_desc);
    }

    /** Sets the display width and height for this preference. */
    public void setStateForPreference(int displayWidth, int displayHeight, int displayId) {
        if (mDisplayWidth == displayWidth && mDisplayHeight == displayHeight
                && displayId == mDisplayId) return;
        mDisplayWidth = displayWidth;
        mDisplayHeight = displayHeight;
        mDisplayId = displayId;

        setStateForPreferenceInternal();
    }

    private void setStateForPreferenceInternal() {
        var displaySizeData = new DisplaySizeData(mContext,
                new DisplayDensityUtils(mContext, (info) -> info.displayId == mDisplayId));
        ExternalDisplaySizePreferenceStateHandler
                seekBarChangeHandler =
                new ExternalDisplaySizePreferenceStateHandler(
                        displaySizeData);

        setMax(displaySizeData.getValues().size() - 1);
        setProgress(displaySizeData.getInitialIndex());
        setContinuousUpdates(false);
        setOnSeekBarChangeListener(seekBarChangeHandler);
    }

    private class ExternalDisplaySizePreferenceStateHandler
            implements SeekBar.OnSeekBarChangeListener {
        private static final long MIN_COMMIT_INTERVAL_MS = 800;
        private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
        private final DisplaySizeData mDisplaySizeData;
        private int mLastDisplayProgress;
        private long mLastCommitTime;
        ExternalDisplaySizePreferenceStateHandler(DisplaySizeData displaySizeData) {
            mDisplaySizeData = displaySizeData;
        }

        final Choreographer.FrameCallback mCommit = this::tryCommitDisplaySizeConfig;

        private void tryCommitDisplaySizeConfig(long unusedFrameTimeNanos) {
            final int displayProgress = getProgress();
            if (displayProgress != mLastDisplayProgress) {
                mDisplaySizeData.commit(displayProgress);
                mLastDisplayProgress = displayProgress;
            }
            mLastCommitTime = SystemClock.elapsedRealtime();
        }

        private void postCommitDelayed() {
            var commitDelayMs = CHANGE_BY_BUTTON_DELAY_MS;
            if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
                commitDelayMs += MIN_COMMIT_INTERVAL_MS;
            }

            final Choreographer choreographer = Choreographer.getInstance();
            choreographer.removeFrameCallback(mCommit);
            choreographer.postFrameCallbackDelayed(mCommit, commitDelayMs);
        }

        @Override
        public void onProgressChanged(@NonNull SeekBar seekBar, int i, boolean b) {
            postCommitDelayed();
        }

        @Override
        public void onStartTrackingTouch(@NonNull SeekBar seekBar) {}

        @Override
        public void onStopTrackingTouch(@NonNull SeekBar seekBar) {}
    }
}