Ensure that animation does not play after brief lapses in app usage

If an app stops using mic/camera for less than three seconds, and then
starts again, only show the dot.

Fixes: 187051104
Test: Went into camera, and switch modes several times
Change-Id: I496046e5d18417e62f1c898340ac6ad06364514a
This commit is contained in:
Nate Myren
2021-05-04 19:12:09 -07:00
parent 5957b1d682
commit 8306072389
3 changed files with 54 additions and 16 deletions

View File

@@ -181,12 +181,19 @@ class PrivacyDotViewController @Inject constructor(
designatedCorner = newCorner
if (animationScheduler.hasPersistentDot) {
designatedCorner!!.visibility = View.VISIBLE
designatedCorner!!.alpha = 0f
designatedCorner!!.animate()
.alpha(1.0f)
.setDuration(300)
.start()
fadeInDot()
}
}
@UiThread
private fun fadeInDot() {
designatedCorner?.let { dot ->
dot.visibility = View.VISIBLE
dot.alpha = 0f
dot.animate()
.alpha(1.0f)
.setDuration(300)
.start()
}
}
@@ -300,9 +307,14 @@ class PrivacyDotViewController @Inject constructor(
private val systemStatusAnimationCallback: SystemStatusAnimationCallback =
object : SystemStatusAnimationCallback {
override fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? {
override fun onSystemStatusAnimationTransitionToPersistentDot(
showAnimation: Boolean
): Animator? {
if (designatedCorner == null) {
return null
} else if (!showAnimation) {
uiExecutor?.execute { fadeInDot() }
return null
}
val alpha = ObjectAnimator.ofFloat(

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.events
import android.os.SystemClock
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.privacy.PrivacyItemController
@@ -59,10 +60,10 @@ class SystemEventCoordinator @Inject constructor(
scheduler.setShouldShowPersistentPrivacyIndicator(false)
}
fun notifyPrivacyItemsChanged() {
fun notifyPrivacyItemsChanged(showAnimation: Boolean = true) {
val event = PrivacyEvent()
event.privacyItems = privacyStateListener.currentPrivacyItems
scheduler.onStatusEvent(event)
scheduler.onStatusEvent(event, showAnimation)
}
private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback {
@@ -90,8 +91,17 @@ class SystemEventCoordinator @Inject constructor(
private val privacyStateListener = object : PrivacyItemController.Callback {
var currentPrivacyItems = listOf<PrivacyItem>()
var previousPrivacyItems = listOf<PrivacyItem>()
var timeLastEmpty = SystemClock.elapsedRealtime()
override fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>) {
if (uniqueItemsMatch(privacyItems, currentPrivacyItems)) {
return
} else if (privacyItems.isEmpty()) {
previousPrivacyItems = currentPrivacyItems
timeLastEmpty = SystemClock.elapsedRealtime()
}
currentPrivacyItems = privacyItems
notifyListeners()
}
@@ -100,10 +110,19 @@ class SystemEventCoordinator @Inject constructor(
if (currentPrivacyItems.isEmpty()) {
notifyPrivacyItemsEmpty()
} else {
notifyPrivacyItemsChanged()
val showAnimation = !uniqueItemsMatch(currentPrivacyItems, previousPrivacyItems) ||
SystemClock.elapsedRealtime() - timeLastEmpty >= DEBOUNCE_TIME
notifyPrivacyItemsChanged(showAnimation)
}
}
// Return true if the lists contain the same permission groups, used by the same UIDs
private fun uniqueItemsMatch(one: List<PrivacyItem>, two: List<PrivacyItem>): Boolean {
return one.map { it.application.uid to it.privacyType.permGroupName }.toSet() ==
two.map { it.application.uid to it.privacyType.permGroupName }.toSet()
}
}
}
private const val DEBOUNCE_TIME = 3000L
private const val TAG = "SystemEventCoordinator"

View File

@@ -90,7 +90,7 @@ class SystemStatusAnimationScheduler @Inject constructor(
coordinator.attachScheduler(this)
}
fun onStatusEvent(event: StatusEvent) {
fun onStatusEvent(event: StatusEvent, showAnimation: Boolean = true) {
// Ignore any updates until the system is up and running
if (isTooEarly() || !isImmersiveIndicatorEnabled()) {
return
@@ -103,7 +103,12 @@ class SystemStatusAnimationScheduler @Inject constructor(
if (DEBUG) {
Log.d(TAG, "scheduling event $event")
}
scheduleEvent(event)
if (showAnimation) {
scheduleEvent(event)
} else if (event.forceVisible) {
hasPersistentDot = true
notifyTransitionToPersistentDot(showAnimation = false)
}
} else {
if (DEBUG) {
Log.d(TAG, "ignoring event $event")
@@ -197,7 +202,7 @@ class SystemStatusAnimationScheduler @Inject constructor(
aSet2.play(chipAnimator).before(systemAnimator)
if (hasPersistentDot) {
val dotAnim = notifyTransitionToPersistentDot()
val dotAnim = notifyTransitionToPersistentDot(showAnimation = true)
if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
}
@@ -209,9 +214,9 @@ class SystemStatusAnimationScheduler @Inject constructor(
}, DELAY)
}
private fun notifyTransitionToPersistentDot(): Animator? {
private fun notifyTransitionToPersistentDot(showAnimation: Boolean): Animator? {
val anims: List<Animator> = listeners.mapNotNull {
it.onSystemStatusAnimationTransitionToPersistentDot()
it.onSystemStatusAnimationTransitionToPersistentDot(showAnimation)
}
if (anims.isNotEmpty()) {
val aSet = AnimatorSet()
@@ -321,7 +326,9 @@ interface SystemStatusAnimationCallback {
@JvmDefault fun onSystemChromeAnimationEnd() {}
// Best method name, change my mind
@JvmDefault fun onSystemStatusAnimationTransitionToPersistentDot(): Animator? { return null }
@JvmDefault fun onSystemStatusAnimationTransitionToPersistentDot(
showAnimation: Boolean
): Animator? { return null }
@JvmDefault fun onHidePersistentDot(): Animator? { return null }
}