xref: /aosp_15_r20/external/android_onboarding/java/com/android/onboarding/nodes/OnboardingGraphNode.kt (revision c625018464ae97c56936c82b1b617e11aa899faa)
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