1 package com.android.onboarding.nodes 2 3 import com.android.onboarding.contracts.annotations.OnboardingNode 4 import java.time.Duration 5 import java.time.Instant 6 7 /** 8 * Basic [IOnboardingGraphNode] representation with data available from a set of 9 * [OnboardingGraphLog.OnboardingEventDelegate] only. 10 */ 11 typealias OnboardingGraphNode = IOnboardingGraphNode<OnboardingGraphLog.OnboardingEventDelegate> 12 13 /** Common data for all onboarding node implementations. */ 14 interface OnboardingGraphNodeData { 15 /** The node's UUID. */ 16 val id: Long 17 18 /** The name of this node. */ 19 val name: String 20 21 /** 22 * Fully qualified name of this entity representing its kind. Expected to be distinct from other 23 * node kinds within the graph. 24 */ 25 val qualifiedName: String 26 get() = "$component/$name" 27 28 val argument: Any? 29 val result: Any? 30 31 /** The time this node entered the graph. */ 32 val start: Instant 33 34 /** The time this node exited the graph. */ 35 val end: Instant 36 37 /** All the graph edges this node has initiated. */ 38 val outgoingEdges: Collection<OnboardingGraphEdge.Outgoing> 39 40 /** 41 * Filtered subset of [outgoingEdges] without the invalid outgoing edges. i.e. edges to non 42 * existent nodes. 43 */ 44 val outgoingEdgesOfValidNodes: Collection<OnboardingGraphEdge.Outgoing> 45 46 /** The graph edge this node has received. */ 47 val incomingEdge: OnboardingGraphEdge.Incoming? 48 val failureReasons: Collection<Throwable> 49 50 /** A list of issue descriptions detected for this node. */ 51 val issues: Collection<String> 52 53 val isFailed: Boolean 54 get() = failureReasons.isNotEmpty() 55 56 /** The node's type. */ 57 val type: Type 58 59 /** The name of the onboarding component that owns this node. */ 60 val component: Component? 61 val isSynchronous: Boolean 62 get() = type == Type.SYNCHRONOUS 63 64 val isComplete: Boolean 65 66 /** Is the node unknown (no known ID supplied)? */ 67 val unknown: Boolean 68 69 /** 70 * The time between node's [start] and [end]. Includes the time this node spent waiting or in the 71 * background. 72 */ 73 val totalRuntime: Duration 74 get() = Duration.between(start, end) 75 76 /** The time this node spend paused. */ 77 val pausedRuntime: Duration 78 79 /** The actual time this node was active. */ 80 val individualRuntime: Duration 81 get() = totalRuntime - pausedRuntime 82 83 /** Calculates the % of total graph duration that this node took. */ percentOfGraphDurationnull84 fun percentOfGraphDuration(graphDuration: Duration): Double = 85 individualRuntime.toNanos().toDouble() / graphDuration.toNanos() 86 87 /** Short string representation of the components uniquely identifying this entity's kind. */ 88 val identity: String 89 get() = "Node(id=$id, qualifiedName=$qualifiedName)" 90 91 enum class Type { 92 UNKNOWN, 93 ACTIVITY, 94 SYNCHRONOUS, 95 } 96 97 @JvmInline 98 value class Component(val name: String) { toStringnull99 override fun toString(): String = name 100 } 101 } 102 103 /** A node in the [OnboardingGraph]. */ 104 interface IOnboardingGraphNode<out TEvent : OnboardingGraphLog.OnboardingEventDelegate> : 105 OnboardingGraphNodeData { 106 /** All the raw onboarding events related to this node. */ 107 val events: Collection<TEvent> 108 get() = spawnedEvents + relatedEvents 109 110 /** All events this node has spawned. */ 111 val spawnedEvents: Collection<TEvent> 112 113 /** All events not spawned by this node, but relating to it. */ 114 val relatedEvents: Collection<TEvent> 115 116 companion object { 117 /** Generate standard name for node with [id] and no name. */ 118 fun unknown(id: Long) = "Unknown(id=$id)" 119 120 /** Generate standard name for node with [id] and no [component]. */ 121 fun unknownComponent(id: Long) = "UnknownComponent(nodeId=$id)" 122 } 123 } 124 125 interface NodeRef { 126 /** An [OnboardingNode.component] this is referring to. */ 127 val nodeComponent: String 128 129 /** An [OnboardingNode.name] this is referring to. */ 130 val nodeName: String 131 } 132