GlassQualityAdapter class

Pure-Dart state machine that automatically selects and adjusts GlassQuality based on observed raster frame performance.

Usage — see file-level documentation above.

Testing — inject synthetic timings via simulateFrameTimings without needing a real GPU raster loop:

adapter.start();
adapter.simulateFrameTimings([
  FakeFrameTiming(rasterUs: 25000), // 25 ms → over budget
]);

Constructors

GlassQualityAdapter({required GlassQuality minQuality, required GlassQuality maxQuality, required int targetFrameMs, required bool allowStepUp, required void onQualityChanged(GlassQuality from, GlassQuality to), GlassQuality? initialQuality, double warmupPremiumThresholdMs = 20.0, double warmupStandardThresholdMs = 28.0, void onWarmupComplete(GlassQuality settled, double p75Ms, int frames)?, bool frostStep = false, void onFrostChanged(bool frostEnabled)?})
Creates a GlassQualityAdapter.

Properties

allowStepUp → bool
Whether the adapter may increase quality after sustained good performance.
final
currentQuality → GlassQuality
The currently effective quality this adapter has decided on.
no setter
frostEnabled → bool
Whether premium glass may draw its frost. Only ever false with frostStep; see there.
no setter
frostStep → bool
Whether premium steps through premium without frost on its way to and from standard.
final
hashCode → int
The hash code for this object.
no setterinherited
initialQuality → GlassQuality?
The quality tier to start at, bypassing Phase 2 (the warm-up benchmark).
final
isRunning → bool
Whether the adapter is currently collecting frame timings.
no setter
lastChangeReason → GlassQualityChangeReason
The reason for the most recent quality change.
no setter
lastFramesMeasured → int?
Frames measured when the most recent quality decision was made.
no setter
lastP75Ms → double?
The P75 raster time (ms) from the most recent Phase 2 warmup decision.
no setter
lastP95Ms → double?
The P95 raster time (ms) from the most recent Phase 3 runtime decision.
no setter
maxQuality → GlassQuality
The highest quality tier the adapter may step up to.
final
minQuality → GlassQuality
The lowest quality tier the adapter may step down to.
final
phase → AdaptivePhase
The current internal phase (probe → warmup → runtime).
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
targetFrameMs → int
The target frame duration in milliseconds (e.g. 16 for 60 Hz, 8 for ProMotion / 120 Hz). Thresholds for degradation and upgrade are derived from this value.
final
usedCachedQuality → bool
Whether the adapter is using a previously settled quality (either from initialQuality or _sessionSettledQuality) and has skipped Phase 2.
no setter
warmupPremiumThresholdMs → double
The P75 warmup threshold (ms) below which the device is classified as capable of GlassQuality.premium.
final
warmupStandardThresholdMs → double
The P75 warmup threshold (ms) at or below which the device is classified as capable of GlassQuality.standard (when P75 ≥ warmupPremiumThresholdMs).
final

Methods

noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
reset() → void
Resets the adapter to Phase 2 and clears all accumulated data.
simulateFrameTimings(List<FrameTiming> timings) → void
Injects synthetic FrameTiming data directly into the phase handlers, bypassing the SchedulerBinding listener registration.
start() → void
Starts the adapter.
stop() → void
Stops the adapter and detaches its frame timing callback.
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Static Properties

cooldownDuration ↔ Duration
Minimum time between consecutive quality changes.
getter/setter pair
degradeWindowCount ↔ int
Number of consecutive over-budget windows that trigger a quality step-down. Default: 2.
getter/setter pair
measurementHeld → bool
Whether at least one holdMeasurement hold is open.
no setter
sessionSettledQuality → GlassQuality?
The currently cached quality for this session, or null if Phase 2 has not yet completed on any adapter instance.
no setter
settleFramesAfterHold ↔ int
Frames dropped after the last hold is released. Default: 120 (about one second at 120 Hz).
getter/setter pair
skipInitialFrames ↔ int
Frames to skip at the very start of Phase 2 before collecting warmup data. This lets shader compilation, first-route transitions, and provider initialisation settle so they don't pollute the warmup benchmark.
getter/setter pair
skipStaticProbeForTesting ↔ bool
When true, the static-probe step (Phase 1) is skipped and the adapter proceeds directly to Phase 2 (warm-up) even on headless test VMs where ImageFilter.isShaderFilterSupported returns false.
getter/setter pair
upgradeWindowCount ↔ int
Number of consecutive under-budget windows that trigger a quality step-up (only when allowStepUp is true). Default: 10.
getter/setter pair
warmupFrames ↔ int
Frames to collect in Phase 2 (warm-up) before making the initial quality decision. Default: 180 ≈ 3 seconds at 60 Hz.
getter/setter pair
windowSize ↔ int
Size of the rolling window used in Phase 3 for P95 calculation. Default: 120 ≈ 2 seconds at 60 Hz.
getter/setter pair

Static Methods

clearSessionCache() → void
Clears the in-session quality cache.
holdMeasurement() → GlassMeasurementHold
Suspends frame measurement, for every adapter, until the returned hold (and every other open hold) is released.
percentileForTesting(List<int> data, int percentile) → int
Visible for testing only: computes percentile using Quickselect.
quickSelectForTesting(List<int> a, int k) → int
Visible for testing only: finds k-th smallest element using Quickselect.
resetMeasurementHoldsForTesting() → void
Clears every hold. For tests only.