1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.haptics.slider 18 19 import kotlinx.coroutines.CoroutineScope 20 import kotlinx.coroutines.Job 21 import kotlinx.coroutines.cancel 22 import kotlinx.coroutines.launch 23 24 /** 25 * Tracker component for a slider. 26 * 27 * The tracker maintains a state machine operated by slider events coming from a 28 * [SliderEventProducer]. An action is executed in each state via a [SliderListener]. 29 * 30 * @property[scope] [CoroutineScope] to launch the collection of [SliderEvent] and state machine 31 * logic. 32 * @property[sliderListener] [SliderListener] to execute actions on a given [SliderState]. 33 * @property[eventProducer] Producer of [SliderEvent] to iterate over a state machine. 34 */ 35 sealed class SliderTracker( 36 protected val scope: CoroutineScope, 37 protected val sliderListener: SliderStateListener, 38 protected val eventProducer: SliderEventProducer, 39 ) { 40 41 /* Reference to the current state of the internal state machine */ 42 var currentState: SliderState = SliderState.IDLE 43 protected set 44 45 /** 46 * Job that launches and maintains the coroutine that collects events and operates the state 47 * machine. 48 */ 49 protected var job: Job? = null 50 51 /** Indicator that the tracker is active and tracking */ 52 var isTracking = false 53 get() = job != null && job?.isActive == true 54 private set 55 56 /** Starts the [Job] that collects slider events and runs the state machine */ 57 fun startTracking() { 58 job = 59 scope.launch { 60 eventProducer.produceEvents().collect { event -> 61 iterateState(event) 62 executeOnState(currentState) 63 } 64 } 65 } 66 67 /** Stops the collection of slider events and the state machine */ 68 fun stopTracking() { 69 job?.cancel("Stopped tracking slider state") 70 job = null 71 resetState() 72 } 73 74 /** 75 * Iterate through the state machine due to a new slider event. As a result, the current state 76 * is modified. 77 * 78 * @param[event] The slider event that is received. 79 */ 80 protected abstract suspend fun iterateState(event: SliderEvent) 81 82 /** 83 * Execute an action based on the state of the state machine. This method should use the 84 * [SliderListener] to act on the current state. 85 * 86 * @param[currentState] A [SliderState] in the state machine 87 */ 88 protected abstract fun executeOnState(currentState: SliderState) 89 90 /** Reset the state machine by setting the current state to [SliderState.IDLE] */ 91 protected open fun resetState() { 92 currentState = SliderState.IDLE 93 } 94 } 95