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:
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user