Asynchronous notif pipeline evaluation

This CL introduces NotifPipelineChoreographer, which can be used to
"schedule" listener invocations at a later time.

In effect, this replaces the following code:

   foo.addListener { expensive() }
   bar.addListener { expensive() }

With:

   val choreographer: NotifPipelineChoreographer = ...
   choreographer.addOnEvalListener { expensive() }
   foo.addListener { choreographer.schedule() }
   bar.addListener { choreographer.schedule() }

This will coalesce the calls to expensive(), which will be evaluated at
some point in the future when the NotifPipelineChoreographer invokes its
registered OnEvalListeners.

The implementation included is based on android.view.Choreographer,
which will perform a scheduled evaluation at most once per frame, in
conjunction with a 100ms timeout to force evaluation.

The NotifPipelineChoreographer is used to coalesce all evaluations of
ShadeListBuilder.buildList, which includes all Pluggable invalidations
and new emissions from the NotifCollection.

Test: atest, perfetto + unlock phone (transition from keyguard) and
verify ShadeListBuilder.buildList is invoked at most once per frame

Fixes: 217800329

Change-Id: I4be70b495bdda5a32a202a92b9b28f2cff3402c9
5 files changed