Merge "Accessibility for privacy status animations" into sc-dev am: 61a46b1718

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15518424

Change-Id: Ia03bd5d47710c26ebb67617ef81bfd658d81868f
This commit is contained in:
bsears
2021-08-17 22:21:20 +00:00
committed by Automerger Merge Worker
5 changed files with 59 additions and 30 deletions

View File

@@ -497,7 +497,12 @@ class PrivacyDotViewController @Inject constructor(
}
if (state.designatedCorner != currentViewState.designatedCorner) {
currentViewState.designatedCorner?.contentDescription = null
state.designatedCorner?.contentDescription = state.contentDescription
updateDesignatedCorner(state.designatedCorner, state.shouldShowDot())
} else if (state.contentDescription != currentViewState.contentDescription) {
state.designatedCorner?.contentDescription = state.contentDescription
}
val shouldShow = state.shouldShowDot()
@@ -514,9 +519,13 @@ class PrivacyDotViewController @Inject constructor(
private val systemStatusAnimationCallback: SystemStatusAnimationCallback =
object : SystemStatusAnimationCallback {
override fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? {
override fun onSystemStatusAnimationTransitionToPersistentDot(
contentDescr: String?
): Animator? {
synchronized(lock) {
nextViewState = nextViewState.copy(systemPrivacyEventIsActive = true)
nextViewState = nextViewState.copy(
systemPrivacyEventIsActive = true,
contentDescription = contentDescr)
}
return null
@@ -620,7 +629,9 @@ private data class ViewState(
val rotation: Int = 0,
val height: Int = 0,
val cornerIndex: Int = -1,
val designatedCorner: View? = null
val designatedCorner: View? = null,
val contentDescription: String? = null
) {
fun shouldShowDot(): Boolean {
return systemPrivacyEventIsActive && !shadeExpanded && !qsExpanded

View File

@@ -34,6 +34,7 @@ interface StatusEvent {
// Whether or not to show an animation for this event
val showAnimation: Boolean
val viewCreator: (context: Context) -> View
var contentDescription: String?
// Update this event with values from another event.
fun updateFromEvent(other: StatusEvent?) {
@@ -50,6 +51,7 @@ class BatteryEvent : StatusEvent {
override val priority = 50
override val forceVisible = false
override val showAnimation = true
override var contentDescription: String? = ""
override val viewCreator: (context: Context) -> View = { context ->
val iv = ImageView(context)
@@ -62,7 +64,9 @@ class BatteryEvent : StatusEvent {
return javaClass.simpleName
}
}
class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
override var contentDescription: String? = null
override val priority = 100
override val forceVisible = true
var privacyItems: List<PrivacyItem> = listOf()
@@ -72,6 +76,7 @@ class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
val v = LayoutInflater.from(context)
.inflate(R.layout.ongoing_privacy_chip, null) as OngoingPrivacyChip
v.privacyList = privacyItems
v.contentDescription = contentDescription
privacyChip = v
v
}
@@ -81,7 +86,9 @@ class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
}
override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean {
return other is PrivacyEvent && other.privacyItems != privacyItems
return other is PrivacyEvent &&
(other.privacyItems != privacyItems ||
other.contentDescription != contentDescription)
}
override fun updateFromEvent(other: StatusEvent?) {
@@ -90,6 +97,9 @@ class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
}
privacyItems = other.privacyItems
contentDescription = other.contentDescription
privacyChip?.contentDescription = other.contentDescription
privacyChip?.privacyList = other.privacyItems
}
}

View File

@@ -34,8 +34,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowView
import javax.inject.Inject
/**
* //TODO: this _probably_ doesn't control a window anymore
* Controls the window for system event animations.
* Controls the view for system event animations.
*/
class SystemEventChipAnimationController @Inject constructor(
private val context: Context,

View File

@@ -16,9 +16,12 @@
package com.android.systemui.statusbar.events
import android.content.Context
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_PRIVACY
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.privacy.PrivacyChipBuilder
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.statusbar.policy.BatteryController
@@ -33,7 +36,8 @@ import javax.inject.Inject
class SystemEventCoordinator @Inject constructor(
private val systemClock: SystemClock,
private val batteryController: BatteryController,
private val privacyController: PrivacyItemController
private val privacyController: PrivacyItemController,
private val context: Context
) {
private lateinit var scheduler: SystemStatusAnimationScheduler
@@ -66,6 +70,11 @@ class SystemEventCoordinator @Inject constructor(
fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) {
val event = PrivacyEvent(showAnimation)
event.privacyItems = privacyStateListener.currentPrivacyItems
event.contentDescription = {
val items = PrivacyChipBuilder(context, event.privacyItems).joinTypes()
context.getString(
R.string.ongoing_privacy_chip_content_multiple_apps, items)
}()
scheduler.onStatusEvent(event)
}

View File

@@ -100,17 +100,20 @@ class SystemStatusAnimationScheduler @Inject constructor(
// Don't deal with threading for now (no need let's be honest)
Assert.isMainThread()
if (event.priority > scheduledEvent?.priority ?: -1 ||
scheduledEvent?.shouldUpdateFromEvent(event) == true) {
if ((event.priority > scheduledEvent?.priority ?: -1) &&
animationState != ANIMATING_OUT &&
(animationState != SHOWING_PERSISTENT_DOT && event.forceVisible)) {
// events can only be scheduled if a higher priority or no other event is in progress
if (DEBUG) {
Log.d(TAG, "scheduling event $event")
}
if (event.showAnimation) {
scheduleEvent(event)
} else if (event.forceVisible) {
hasPersistentDot = true
notifyTransitionToPersistentDot()
scheduleEvent(event)
} else if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
if (DEBUG) {
Log.d(TAG, "updating current event from: $event")
}
scheduledEvent?.updateFromEvent(event)
} else {
if (DEBUG) {
Log.d(TAG, "ignoring event $event")
@@ -142,24 +145,18 @@ class SystemStatusAnimationScheduler @Inject constructor(
* Clear the scheduled event (if any) and schedule a new one
*/
private fun scheduleEvent(event: StatusEvent) {
if (animationState == ANIMATING_OUT ||
(animationState == SHOWING_PERSISTENT_DOT && event.forceVisible)) {
// do not schedule an event or change the current one
return
}
scheduledEvent = event
// If we are showing the chip, possibly update the current event, rather than replacing
if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
scheduledEvent?.updateFromEvent(event)
return
} else {
scheduledEvent = event
}
if (scheduledEvent!!.forceVisible) {
if (event.forceVisible) {
hasPersistentDot = true
}
// If animations are turned off, we'll transition directly to the dot
if (!event.showAnimation && event.forceVisible) {
notifyTransitionToPersistentDot()
return
}
// Schedule the animation to start after a debounce period
cancelExecutionRunnable = executor.executeDelayed({
cancelExecutionRunnable = null
@@ -218,7 +215,7 @@ class SystemStatusAnimationScheduler @Inject constructor(
private fun notifyTransitionToPersistentDot(): Animator? {
val anims: List<Animator> = listeners.mapNotNull {
it.onSystemStatusAnimationTransitionToPersistentDot()
it.onSystemStatusAnimationTransitionToPersistentDot(scheduledEvent?.contentDescription)
}
if (anims.isNotEmpty()) {
val aSet = AnimatorSet()
@@ -346,7 +343,10 @@ interface SystemStatusAnimationCallback {
@JvmDefault fun onSystemChromeAnimationEnd() {}
// Best method name, change my mind
@JvmDefault fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? { return null }
@JvmDefault
fun onSystemStatusAnimationTransitionToPersistentDot(contentDescription: String?): Animator? {
return null
}
@JvmDefault fun onHidePersistentDot(): Animator? { return null }
}