1 package com.android.onboarding.contracts 2 3 import android.app.Activity 4 import android.content.Context 5 import android.content.Intent 6 import com.android.onboarding.nodes.AndroidOnboardingGraphLog 7 import com.android.onboarding.nodes.OnboardingEvent 8 import java.util.UUID 9 import javax.inject.Qualifier 10 11 typealias NodeId = Long 12 13 /** 14 * A DI qualifier to inject node ID where applicable. Consuming module should scope this to a given 15 * activity's lifecycle. 16 */ 17 @Retention(AnnotationRetention.RUNTIME) @Qualifier annotation class OnboardingNodeId 18 19 /** 20 * Marks entities that require awareness of onboarding node currently being executed 21 * 22 * @property nodeId the ID of the currently executing node 23 */ 24 interface NodeAware { 25 @OnboardingNodeId val nodeId: NodeId 26 } 27 28 /** Extra key used when storing a node id */ 29 const val EXTRA_ONBOARDING_NODE_ID = "com.android.onboarding.ONBOARDING_NODE_ID" 30 31 const val UNKNOWN_NODE_ID: NodeId = -1L 32 33 val Intent.nodeId: NodeId 34 get() = <lambda>null35 getLongExtra(EXTRA_ONBOARDING_NODE_ID, UNKNOWN_NODE_ID).let { 36 if (it == UNKNOWN_NODE_ID) { 37 val id = UUID.randomUUID().leastSignificantBits 38 this.putExtra(EXTRA_ONBOARDING_NODE_ID, id) 39 id 40 } else { 41 it 42 } 43 } 44 45 val Activity.nodeId: NodeId 46 get() { 47 intent = intent ?: Intent() 48 return intent.nodeId 49 } 50 51 /** 52 * Extract a [NodeId] from this [Context] making an assumption that this is an [Activity]. Returns 53 * unknown [UNKNOWN_NODE_ID] if this [Context] is not an [Activity]. 54 */ Contextnull55fun Context.activityNodeId(): NodeId = 56 if (this is Activity) { 57 nodeId 58 } else { 59 UNKNOWN_NODE_ID 60 } 61 62 /** Mark the executing node as failed with [reason]. */ failNodenull63fun Activity.failNode(reason: String? = null) { 64 AndroidOnboardingGraphLog.log(OnboardingEvent.ActivityNodeFail(nodeId, reason)) 65 } 66