Merge "Accessibility for privacy status animations" into sc-dev

This commit is contained in:
bsears
2021-08-17 22:20:48 +00:00
committed by Android (Google) Code Review
5 changed files with 59 additions and 30 deletions

View File

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

View File

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

View File

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

View File

@@ -16,9 +16,12 @@
package com.android.systemui.statusbar.events package com.android.systemui.statusbar.events
import android.content.Context
import android.provider.DeviceConfig import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_PRIVACY import android.provider.DeviceConfig.NAMESPACE_PRIVACY
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.privacy.PrivacyChipBuilder
import com.android.systemui.privacy.PrivacyItem import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController
@@ -33,7 +36,8 @@ import javax.inject.Inject
class SystemEventCoordinator @Inject constructor( class SystemEventCoordinator @Inject constructor(
private val systemClock: SystemClock, private val systemClock: SystemClock,
private val batteryController: BatteryController, private val batteryController: BatteryController,
private val privacyController: PrivacyItemController private val privacyController: PrivacyItemController,
private val context: Context
) { ) {
private lateinit var scheduler: SystemStatusAnimationScheduler private lateinit var scheduler: SystemStatusAnimationScheduler
@@ -66,6 +70,11 @@ class SystemEventCoordinator @Inject constructor(
fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) { fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) {
val event = PrivacyEvent(showAnimation) val event = PrivacyEvent(showAnimation)
event.privacyItems = privacyStateListener.currentPrivacyItems 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) 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) // Don't deal with threading for now (no need let's be honest)
Assert.isMainThread() Assert.isMainThread()
if (event.priority > scheduledEvent?.priority ?: -1 || if ((event.priority > scheduledEvent?.priority ?: -1) &&
scheduledEvent?.shouldUpdateFromEvent(event) == true) { 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) { if (DEBUG) {
Log.d(TAG, "scheduling event $event") Log.d(TAG, "scheduling event $event")
} }
if (event.showAnimation) {
scheduleEvent(event) scheduleEvent(event)
} else if (event.forceVisible) { } else if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
hasPersistentDot = true if (DEBUG) {
notifyTransitionToPersistentDot() Log.d(TAG, "updating current event from: $event")
} }
scheduledEvent?.updateFromEvent(event)
} else { } else {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "ignoring event $event") 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 * Clear the scheduled event (if any) and schedule a new one
*/ */
private fun scheduleEvent(event: StatusEvent) { private fun scheduleEvent(event: StatusEvent) {
if (animationState == ANIMATING_OUT || scheduledEvent = event
(animationState == SHOWING_PERSISTENT_DOT && event.forceVisible)) {
// do not schedule an event or change the current one
return
}
// If we are showing the chip, possibly update the current event, rather than replacing if (event.forceVisible) {
if (scheduledEvent?.shouldUpdateFromEvent(event) == true) {
scheduledEvent?.updateFromEvent(event)
return
} else {
scheduledEvent = event
}
if (scheduledEvent!!.forceVisible) {
hasPersistentDot = true 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 // Schedule the animation to start after a debounce period
cancelExecutionRunnable = executor.executeDelayed({ cancelExecutionRunnable = executor.executeDelayed({
cancelExecutionRunnable = null cancelExecutionRunnable = null
@@ -218,7 +215,7 @@ class SystemStatusAnimationScheduler @Inject constructor(
private fun notifyTransitionToPersistentDot(): Animator? { private fun notifyTransitionToPersistentDot(): Animator? {
val anims: List<Animator> = listeners.mapNotNull { val anims: List<Animator> = listeners.mapNotNull {
it.onSystemStatusAnimationTransitionToPersistentDot() it.onSystemStatusAnimationTransitionToPersistentDot(scheduledEvent?.contentDescription)
} }
if (anims.isNotEmpty()) { if (anims.isNotEmpty()) {
val aSet = AnimatorSet() val aSet = AnimatorSet()
@@ -346,7 +343,10 @@ interface SystemStatusAnimationCallback {
@JvmDefault fun onSystemChromeAnimationEnd() {} @JvmDefault fun onSystemChromeAnimationEnd() {}
// Best method name, change my mind // 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 } @JvmDefault fun onHidePersistentDot(): Animator? { return null }
} }