Merge changes I8da85eb9,I5f91a776 into udc-dev

* changes:
  Provides text preview whenever the seekbar progress changes
  Fix seekbar flickers when changing the font size
This commit is contained in:
Candice Lo
2023-05-04 06:33:14 +00:00
committed by Android (Google) Code Review
4 changed files with 122 additions and 34 deletions

View File

@@ -15,11 +15,12 @@
*/
package com.android.systemui.accessibility.fontscaling
import android.annotation.WorkerThread
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.database.ContentObserver
import android.os.Bundle
import android.os.Handler
import android.provider.Settings
import android.util.TypedValue
import android.view.LayoutInflater
@@ -27,13 +28,18 @@ 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.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SystemSettings
import java.util.concurrent.Executor
import com.android.systemui.util.time.SystemClock
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.roundToInt
/** The Dialog that contains a seekbar for changing the font size. */
@@ -41,17 +47,31 @@ class FontScalingDialog(
context: Context,
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
@Background private val backgroundExecutor: Executor
private val systemClock: SystemClock,
@Main mainHandler: Handler,
@Background private val backgroundDelayableExecutor: DelayableExecutor
) : SystemUIDialog(context) {
private val MIN_UPDATE_INTERVAL_MS: Long = 800
private val CHANGE_BY_SEEKBAR_DELAY_MS: Long = 100
private val CHANGE_BY_BUTTON_DELAY_MS: Long = 300
private val strEntryValues: Array<String> =
context.resources.getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
private lateinit var title: TextView
private lateinit var doneButton: Button
private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView
private var lastProgress: Int = -1
private var lastProgress: AtomicInteger = AtomicInteger(-1)
private var lastUpdateTime: Long = 0
private var cancelUpdateFontScaleRunnable: Runnable? = null
private val configuration: Configuration = Configuration(context.resources.configuration)
private val fontSizeObserver =
object : ContentObserver(mainHandler) {
override fun onChange(selfChange: Boolean) {
lastUpdateTime = systemClock.elapsedRealtime()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
setTitle(R.string.font_scaling_dialog_title)
setView(LayoutInflater.from(context).inflate(R.layout.font_scaling_dialog, null))
@@ -79,21 +99,21 @@ class FontScalingDialog(
seekBarWithIconButtonsView.setMax((strEntryValues).size - 1)
val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f)
lastProgress = fontSizeValueToIndex(currentScale)
seekBarWithIconButtonsView.setProgress(lastProgress)
lastProgress.set(fontSizeValueToIndex(currentScale))
seekBarWithIconButtonsView.setProgress(lastProgress.get())
seekBarWithIconButtonsView.setOnSeekBarChangeListener(
object : OnSeekBarChangeListener {
var isTrackingTouch = false
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)
} else {
// Provide preview configuration for text instead of changing the system
// font scale before users release their finger from the seekbar.
createTextPreview(progress)
changeFontSize(progress, CHANGE_BY_BUTTON_DELAY_MS)
}
}
@@ -103,26 +123,50 @@ class FontScalingDialog(
override fun onStopTrackingTouch(seekBar: SeekBar) {
isTrackingTouch = false
changeFontSize(seekBar.progress)
changeFontSize(seekBar.progress, CHANGE_BY_SEEKBAR_DELAY_MS)
}
}
)
doneButton.setOnClickListener { dismiss() }
systemSettings.registerContentObserver(Settings.System.FONT_SCALE, fontSizeObserver)
}
private fun changeFontSize(progress: Int) {
if (progress != lastProgress) {
/**
* Avoid SeekBar flickers when changing font scale. See the description from Setting at {@link
* TextReadingPreviewController#postCommitDelayed} for the reasons of flickers.
*/
@MainThread
fun updateFontScaleDelayed(delayMsFromSource: Long) {
var delayMs = delayMsFromSource
if (systemClock.elapsedRealtime() - lastUpdateTime < MIN_UPDATE_INTERVAL_MS) {
delayMs += MIN_UPDATE_INTERVAL_MS
}
cancelUpdateFontScaleRunnable?.run()
cancelUpdateFontScaleRunnable =
backgroundDelayableExecutor.executeDelayed({ updateFontScale() }, delayMs)
}
override fun stop() {
cancelUpdateFontScaleRunnable?.run()
cancelUpdateFontScaleRunnable = null
systemSettings.unregisterContentObserver(fontSizeObserver)
}
@MainThread
private fun changeFontSize(progress: Int, changedWithDelay: Long) {
if (progress != lastProgress.get()) {
lastProgress.set(progress)
if (!fontSizeHasBeenChangedFromTile) {
backgroundExecutor.execute { updateSecureSettingsIfNeeded() }
backgroundDelayableExecutor.execute { updateSecureSettingsIfNeeded() }
fontSizeHasBeenChangedFromTile = true
}
backgroundExecutor.execute { updateFontScale(strEntryValues[progress]) }
lastProgress = progress
updateFontScaleDelayed(changedWithDelay)
}
}
@WorkerThread
private fun fontSizeValueToIndex(value: Float): Int {
var lastValue = strEntryValues[0].toFloat()
for (i in 1 until strEntryValues.size) {
@@ -150,8 +194,8 @@ class FontScalingDialog(
}
@WorkerThread
fun updateFontScale(newScale: String) {
systemSettings.putString(Settings.System.FONT_SCALE, newScale)
fun updateFontScale() {
systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[lastProgress.get()])
}
@WorkerThread

View File

@@ -17,7 +17,6 @@ package com.android.systemui.qs.tiles
import android.content.Intent
import android.os.Handler
import android.os.HandlerExecutor
import android.os.Looper
import android.provider.Settings
import android.view.View
@@ -40,8 +39,10 @@ import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SystemSettings
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
class FontScalingTile
@@ -50,7 +51,7 @@ constructor(
host: QSHost,
uiEventLogger: QsEventLogger,
@Background backgroundLooper: Looper,
@Main mainHandler: Handler,
@Main private val mainHandler: Handler,
falsingManager: FalsingManager,
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
@@ -59,7 +60,9 @@ constructor(
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
private val featureFlags: FeatureFlags
private val systemClock: SystemClock,
private val featureFlags: FeatureFlags,
@Background private val backgroundDelayableExecutor: DelayableExecutor
) :
QSTileImpl<QSTile.State?>(
host,
@@ -89,7 +92,9 @@ constructor(
mContext,
systemSettings,
secureSettings,
HandlerExecutor(mHandler)
systemClock,
mainHandler,
backgroundDelayableExecutor
)
if (view != null) {
dialogLaunchAnimator.showFromView(

View File

@@ -50,10 +50,14 @@ private const val OFF: Int = 0
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class FontScalingDialogTest : SysuiTestCase() {
private val MIN_UPDATE_INTERVAL_MS: Long = 800
private val CHANGE_BY_SEEKBAR_DELAY_MS: Long = 100
private val CHANGE_BY_BUTTON_DELAY_MS: Long = 300
private lateinit var fontScalingDialog: FontScalingDialog
private lateinit var systemSettings: SystemSettings
private lateinit var secureSettings: SecureSettings
private lateinit var backgroundExecutor: FakeExecutor
private lateinit var systemClock: FakeSystemClock
private lateinit var backgroundDelayableExecutor: FakeExecutor
private val fontSizeValueArray: Array<String> =
mContext
.getResources()
@@ -67,10 +71,20 @@ class FontScalingDialogTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
val mainHandler = Handler(TestableLooper.get(this).getLooper())
systemSettings = FakeSettings()
// Guarantee that the systemSettings always starts with the default font scale.
systemSettings.putFloat(Settings.System.FONT_SCALE, 1.0f)
secureSettings = FakeSettings()
backgroundExecutor = FakeExecutor(FakeSystemClock())
systemClock = FakeSystemClock()
backgroundDelayableExecutor = FakeExecutor(systemClock)
fontScalingDialog =
spy(FontScalingDialog(mContext, systemSettings, secureSettings, backgroundExecutor))
FontScalingDialog(
mContext,
systemSettings,
secureSettings,
systemClock,
mainHandler,
backgroundDelayableExecutor
)
}
@Test
@@ -96,9 +110,14 @@ class FontScalingDialogTest : SysuiTestCase() {
val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
seekBarWithIconButtonsView.setProgress(0)
backgroundDelayableExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
iconEndFrame.performClick()
backgroundExecutor.runAllReady()
backgroundDelayableExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
assertThat(seekBar.getProgress()).isEqualTo(1)
@@ -117,9 +136,14 @@ class FontScalingDialogTest : SysuiTestCase() {
val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
seekBarWithIconButtonsView.setProgress(fontSizeValueArray.size - 1)
backgroundDelayableExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
iconStartFrame.performClick()
backgroundExecutor.runAllReady()
backgroundDelayableExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
@@ -139,7 +163,7 @@ class FontScalingDialogTest : SysuiTestCase() {
// Default seekbar progress for font size is 1, set it to another progress 0
seekBarWithIconButtonsView.setProgress(0)
backgroundExecutor.runAllReady()
backgroundDelayableExecutor.runAllReady()
val currentSettings =
secureSettings.getInt(
@@ -153,6 +177,7 @@ class FontScalingDialogTest : SysuiTestCase() {
@Test
fun dragSeekbar_systemFontSizeSettingsDoesNotChange() {
fontScalingDialog = spy(fontScalingDialog)
val slider: SeekBarWithIconButtonsView = spy(SeekBarWithIconButtonsView(mContext))
whenever(
fontScalingDialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider)
@@ -169,7 +194,9 @@ class FontScalingDialogTest : SysuiTestCase() {
// OnSeekBarChangeListener and the seekbar could get updated progress value
// in onStopTrackingTouch.
seekBar.progress = 0
backgroundExecutor.runAllReady()
backgroundDelayableExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
// Verify that the scale of font size remains the default value 1.0f.
var systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
@@ -177,7 +204,9 @@ class FontScalingDialogTest : SysuiTestCase() {
// Simulate releasing the finger from the seekbar.
seekBarChangeCaptor.value.onStopTrackingTouch(seekBar)
backgroundExecutor.runAllReady()
backgroundDelayableExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
// Verify that the scale of font size has been updated.
systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
@@ -188,6 +217,7 @@ class FontScalingDialogTest : SysuiTestCase() {
@Test
fun dragSeekBar_createTextPreview() {
fontScalingDialog = spy(fontScalingDialog)
val slider: SeekBarWithIconButtonsView = spy(SeekBarWithIconButtonsView(mContext))
whenever(
fontScalingDialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider)
@@ -205,7 +235,8 @@ class FontScalingDialogTest : SysuiTestCase() {
/* progress= */ 0,
/* fromUser= */ false
)
backgroundExecutor.runAllReady()
backgroundDelayableExecutor.advanceClockToNext()
backgroundDelayableExecutor.runAllReady()
verify(fontScalingDialog).createTextPreview(/* index= */ 0)
fontScalingDialog.dismiss()

View File

@@ -33,10 +33,12 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -61,6 +63,8 @@ class FontScalingTileTest : SysuiTestCase() {
@Mock private lateinit var uiEventLogger: QsEventLogger
private lateinit var testableLooper: TestableLooper
private lateinit var systemClock: FakeSystemClock
private lateinit var backgroundDelayableExecutor: FakeExecutor
private lateinit var fontScalingTile: FontScalingTile
val featureFlags = FakeFeatureFlags()
@@ -70,6 +74,8 @@ class FontScalingTileTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
`when`(qsHost.getContext()).thenReturn(mContext)
systemClock = FakeSystemClock()
backgroundDelayableExecutor = FakeExecutor(systemClock)
fontScalingTile =
FontScalingTile(
@@ -85,7 +91,9 @@ class FontScalingTileTest : SysuiTestCase() {
dialogLaunchAnimator,
FakeSettings(),
FakeSettings(),
featureFlags
FakeSystemClock(),
featureFlags,
backgroundDelayableExecutor,
)
fontScalingTile.initialize()
testableLooper.processAllMessages()