summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt76
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt10
4 files changed, 118 insertions, 30 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
index c9579d5e1356..a5b7878f22aa 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -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,8 +99,8 @@ 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 {
@@ -89,7 +109,7 @@ class FontScalingDialog(
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (!isTrackingTouch) {
// The seekbar progress is changed by icon buttons
- changeFontSize(progress)
+ changeFontSize(progress, CHANGE_BY_BUTTON_DELAY_MS)
} else {
// Provide preview configuration for text instead of changing the system
// font scale before users release their finger from the seekbar.
@@ -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)
+ }
+
+ /**
+ * 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)
}
- private fun changeFontSize(progress: Int) {
- if (progress != lastProgress) {
+ 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
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 12d98473ff07..c013486b83e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -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(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
index 353a7c370ab6..f10c21bc514a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -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()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index 1d6f225dd0a3..ddbfca57e688 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -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()