1 package com.android.onboarding.nodes 2 3 import com.android.onboarding.OnboardingProtos 4 import com.android.onboarding.contracts.annotations.OnboardingNode 5 import com.google.common.io.BaseEncoding 6 import java.time.Instant 7 8 /** Possible Events. */ 9 sealed interface OnboardingEvent : OnboardingGraphLog.OnboardingEventDelegate { 10 override val nodeName: String 11 override val nodeComponent: String 12 override val nodeId: Long 13 override val timestamp: Instant 14 15 // LINT.IfChange 16 override val source: OnboardingEvent 17 get() = this 18 19 /** Writes this event to a string which can be parsed by [OnboardingEvent.deserialize]. */ serializeToStringnull20 fun serializeToString(): String { 21 return BaseEncoding.base64().encode(serialize().toByteArray()) 22 } 23 serializenull24 fun serialize(): OnboardingProtos.LogProto 25 26 /** Marker interface for events containing an intent data. */ 27 interface WithIntent { 28 /** An intent related to this event. */ 29 val intent: IntentData? 30 } 31 32 /** Marker interface for events containing a result. */ 33 interface WithResult { 34 /** A result produced by the target node. */ 35 val result: Any? 36 } 37 38 /** Marker interface for events containing an argument. */ 39 interface WithArgument { 40 /** The argument supplied for launching target node with. */ 41 val argument: Any? 42 } 43 44 /** Marker interface for events containing a source node id. */ 45 interface WithSource { 46 /** The id of the source node being interacted with. */ 47 val sourceNodeId: Long 48 } 49 50 /** An [OnboardingEvent] spawned only from contracts implemented by activities. */ 51 sealed interface OnboardingActivityEvent : OnboardingEvent 52 53 /** 54 * At [timestamp], a target [android.app.Activity] with id [nodeId] has been launched from 55 * [sourceNodeId] by invoking the [nodeName] contract from inside the [sourceNodeId] node with 56 * [argument] without expecting a result. This implies that [sourceNodeId] is finishing and does 57 * not expect to be returned to. 58 * 59 * Spawned at [sourceNodeId]. 60 * 61 * @property nodeId target node id. 62 * @property nodeName target node name. 63 * @property nodeComponent target node component. 64 * @property sourceNodeId source node id. 65 */ 66 data class ActivityNodeExecutedDirectly( 67 override val nodeName: String, 68 override val nodeComponent: String, 69 override val sourceNodeId: Long, 70 override val nodeId: Long, 71 override val argument: Any?, 72 override val timestamp: Instant = Instant.now(), 73 ) : OnboardingActivityEvent, WithArgument, WithSource { 74 constructor( 75 sourceNodeId: Long, 76 nodeId: Long, 77 nodeClass: Class<*>, 78 argument: Any? = null, 79 timestamp: Instant = Instant.now(), 80 ) : this( 81 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 82 sourceNodeId = sourceNodeId, 83 nodeId = nodeId, 84 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 85 argument = argument, 86 timestamp = timestamp, 87 ) 88 serializenull89 override fun serialize(): OnboardingProtos.LogProto { 90 return OnboardingProtos.LogProto.newBuilder() 91 .setActivityNodeExecutedDirectly( 92 OnboardingProtos.ActivityNodeExecutedDirectlyProto.newBuilder() 93 .setSourceNodeId(sourceNodeId) 94 .setNodeId(nodeId) 95 .setNodeName(nodeName) 96 .setNodeComponent(nodeComponent) 97 // .setArgument(argument) 98 .setTimestamp(timestamp.toEpochMilli()) 99 .build() 100 ) 101 .build() 102 } 103 104 companion object { fromProtonull105 fun fromProto( 106 proto: OnboardingProtos.ActivityNodeExecutedDirectlyProto, 107 timestamp: Instant?, 108 ) = 109 ActivityNodeExecutedDirectly( 110 sourceNodeId = proto.sourceNodeId, 111 nodeId = proto.nodeId, 112 nodeName = proto.nodeName, 113 nodeComponent = proto.nodeComponent, 114 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 115 argument = null, 116 ) 117 } 118 } 119 120 /** 121 * At [timestamp], an [android.app.Activity] with id [nodeId] is using the [nodeName] contract to 122 * validate intent [intent]. 123 * 124 * Spawned at [nodeId]. 125 */ 126 data class ActivityNodeValidating( 127 override val nodeName: String, 128 override val nodeComponent: String, 129 override val nodeId: Long, 130 override val intent: IntentData? = null, 131 override val timestamp: Instant = Instant.now(), 132 ) : OnboardingActivityEvent, WithIntent { 133 constructor( 134 nodeId: Long, 135 nodeClass: Class<*>, 136 intent: IntentData? = null, 137 timestamp: Instant = Instant.now(), 138 ) : this( 139 nodeId = nodeId, 140 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 141 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 142 intent = intent, 143 timestamp = timestamp, 144 ) 145 146 override fun serialize(): OnboardingProtos.LogProto { 147 return OnboardingProtos.LogProto.newBuilder() 148 .setActivityNodeValidating( 149 OnboardingProtos.ActivityNodeValidatingProto.newBuilder() 150 .setNodeId(nodeId) 151 .setNodeName(nodeName) 152 .setNodeComponent(nodeComponent) 153 // .setIntent(intent) 154 .setTimestamp(timestamp.toEpochMilli()) 155 .build() 156 ) 157 .build() 158 } 159 160 companion object { 161 fun fromProto(proto: OnboardingProtos.ActivityNodeValidatingProto, timestamp: Instant?) = 162 ActivityNodeValidating( 163 nodeId = proto.nodeId, 164 nodeName = proto.nodeName, 165 nodeComponent = proto.nodeComponent, 166 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 167 ) 168 } 169 } 170 171 /** 172 * At [timestamp], an [android.app.Activity] with id [nodeId] has failed validation of [intent] 173 * using the [nodeName] contract. The exception was [exception]. 174 * 175 * Spawned at [nodeId]. 176 */ 177 data class ActivityNodeFailedValidation( 178 override val nodeName: String, 179 override val nodeComponent: String, 180 override val nodeId: Long, 181 val exception: Throwable = IllegalArgumentException("Failed validation"), 182 override val intent: IntentData? = null, 183 override val timestamp: Instant = Instant.now(), 184 ) : OnboardingActivityEvent, WithIntent { 185 constructor( 186 nodeId: Long, 187 nodeClass: Class<*>, 188 exception: Throwable = IllegalArgumentException("Failed validation"), 189 intent: IntentData? = null, 190 timestamp: Instant = Instant.now(), 191 ) : this( 192 nodeId = nodeId, 193 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 194 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 195 exception = exception, 196 intent = intent, 197 timestamp = timestamp, 198 ) 199 serializenull200 override fun serialize(): OnboardingProtos.LogProto { 201 return OnboardingProtos.LogProto.newBuilder() 202 .setActivityNodeFailedValidation( 203 OnboardingProtos.ActivityNodeFailedValidationProto.newBuilder() 204 .setNodeId(nodeId) 205 .setNodeName(nodeName) 206 .setNodeComponent(nodeComponent) 207 // .setException(exception) 208 // .setIntent(IntentData(intent?.action ?: "", mapOf())) 209 .setTimestamp(timestamp.toEpochMilli()) 210 .build() 211 ) 212 .build() 213 } 214 215 companion object { fromProtonull216 fun fromProto( 217 proto: OnboardingProtos.ActivityNodeFailedValidationProto, 218 timestamp: Instant?, 219 ) = 220 ActivityNodeFailedValidation( 221 nodeId = proto.nodeId, 222 nodeName = proto.nodeName, 223 nodeComponent = proto.nodeComponent, 224 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 225 ) 226 } 227 } 228 229 /** 230 * At [timestamp], an [android.app.Activity] with id [nodeId] is extracting the argument from 231 * [intent] using the [nodeName] contract. 232 * 233 * Spawned at [nodeId]. 234 */ 235 data class ActivityNodeExtractArgument( 236 override val nodeName: String, 237 override val nodeComponent: String, 238 override val nodeId: Long, 239 override val intent: IntentData, 240 override val timestamp: Instant = Instant.now(), 241 ) : OnboardingActivityEvent, WithIntent { 242 constructor( 243 nodeId: Long, 244 nodeClass: Class<*>, 245 intent: IntentData, 246 timestamp: Instant = Instant.now(), 247 ) : this( 248 nodeId = nodeId, 249 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 250 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 251 intent = intent, 252 timestamp = timestamp, 253 ) 254 255 override fun serialize(): OnboardingProtos.LogProto { 256 return OnboardingProtos.LogProto.newBuilder() 257 .setActivityNodeExtractArgument( 258 OnboardingProtos.ActivityNodeExtractArgumentProto.newBuilder() 259 .setNodeId(nodeId) 260 .setNodeName(nodeName) 261 .setNodeComponent(nodeComponent) 262 .setIntent( 263 OnboardingProtos.IntentDataProto.newBuilder().setAction(intent.action ?: "").build() 264 ) 265 .setTimestamp(timestamp.toEpochMilli()) 266 .build() 267 ) 268 .build() 269 } 270 271 companion object { 272 fun fromProto(proto: OnboardingProtos.ActivityNodeExtractArgumentProto, timestamp: Instant?) = 273 ActivityNodeExtractArgument( 274 nodeId = proto.nodeId, 275 nodeName = proto.nodeName, 276 nodeComponent = proto.nodeComponent, 277 intent = 278 IntentData( 279 if (proto.hasIntent()) proto.intent.action else "", 280 mapOf(), 281 ), 282 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 283 ) 284 } 285 } 286 287 /** 288 * At [timestamp], an [android.app.Activity] with id [nodeId] has extracted [argument] using the 289 * [nodeName] contract. 290 * 291 * Spawned at [nodeId]. 292 */ 293 data class ActivityNodeArgumentExtracted( 294 override val nodeName: String, 295 override val nodeComponent: String, 296 override val nodeId: Long, 297 override val argument: Any?, 298 override val timestamp: Instant = Instant.now(), 299 ) : OnboardingActivityEvent, WithArgument { 300 constructor( 301 nodeId: Long, 302 nodeClass: Class<*>, 303 argument: Any? = null, 304 timestamp: Instant = Instant.now(), 305 ) : this( 306 nodeId = nodeId, 307 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 308 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 309 argument = argument, 310 timestamp = timestamp, 311 ) 312 serializenull313 override fun serialize(): OnboardingProtos.LogProto { 314 return OnboardingProtos.LogProto.newBuilder() 315 .setActivityNodeArgumentExtracted( 316 OnboardingProtos.ActivityNodeArgumentExtractedProto.newBuilder() 317 .setNodeId(nodeId) 318 .setNodeName(nodeName) 319 .setNodeComponent(nodeComponent) 320 // setArgument(argument) 321 .setTimestamp(timestamp.toEpochMilli()) 322 .build() 323 ) 324 .build() 325 } 326 327 companion object { fromProtonull328 fun fromProto( 329 proto: OnboardingProtos.ActivityNodeArgumentExtractedProto, 330 timestamp: Instant?, 331 ) = 332 ActivityNodeArgumentExtracted( 333 nodeId = proto.nodeId, 334 nodeName = proto.nodeName, 335 nodeComponent = proto.nodeComponent, 336 argument = null, 337 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 338 ) 339 } 340 } 341 342 /** 343 * At [timestamp], an [android.app.Activity] with id [nodeId] has set the result to [result] using 344 * the [nodeName] contract. 345 * 346 * Spawned at [nodeId]. 347 */ 348 data class ActivityNodeSetResult( 349 override val nodeName: String, 350 override val nodeComponent: String, 351 override val nodeId: Long, 352 override val result: Any?, 353 override val timestamp: Instant = Instant.now(), 354 ) : OnboardingActivityEvent, WithResult { 355 constructor( 356 nodeId: Long, 357 nodeClass: Class<*>, 358 result: Any?, 359 timestamp: Instant = Instant.now(), 360 ) : this( 361 nodeId = nodeId, 362 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 363 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 364 result = result, 365 timestamp = timestamp, 366 ) 367 368 override fun serialize(): OnboardingProtos.LogProto { 369 return OnboardingProtos.LogProto.newBuilder() 370 .setActivityNodeSetResult( 371 OnboardingProtos.ActivityNodeSetResultProto.newBuilder() 372 .setNodeId(nodeId) 373 .setNodeName(nodeName) 374 .setNodeComponent(nodeComponent) 375 // setResult(result) 376 .setTimestamp(timestamp.toEpochMilli()) 377 .build() 378 ) 379 .build() 380 } 381 382 companion object { 383 fun fromProto(proto: OnboardingProtos.ActivityNodeSetResultProto, timestamp: Instant?) = 384 ActivityNodeSetResult( 385 nodeId = proto.nodeId, 386 nodeName = proto.nodeName, 387 nodeComponent = proto.nodeComponent, 388 result = null, 389 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 390 ) 391 } 392 } 393 394 /** 395 * At [timestamp], an [android.app.Activity] with id [nodeId] has failed the [nodeName] contract 396 * because of [reason]. 397 * 398 * Spawned at [nodeId]. 399 */ 400 data class ActivityNodeFail( 401 override val nodeId: Long, 402 val reason: String?, 403 override val timestamp: Instant = Instant.now(), 404 ) : OnboardingActivityEvent { 405 override val nodeName: String = IOnboardingGraphNode.unknown(nodeId) 406 override val nodeComponent: String = IOnboardingGraphNode.unknownComponent(nodeId) 407 serializenull408 override fun serialize(): OnboardingProtos.LogProto { 409 return OnboardingProtos.LogProto.newBuilder() 410 .setActivityNodeFail( 411 OnboardingProtos.ActivityNodeFailProto.newBuilder() 412 .setNodeId(nodeId) 413 .setReason(reason ?: "") 414 .setTimestamp(timestamp.toEpochMilli()) 415 .build() 416 ) 417 .build() 418 } 419 420 companion object { fromProtonull421 fun fromProto(proto: OnboardingProtos.ActivityNodeFailProto, timestamp: Instant?) = 422 ActivityNodeFail( 423 nodeId = proto.nodeId, 424 reason = proto.reason, 425 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 426 ) 427 } 428 } 429 430 /** 431 * At [timestamp], a target [android.app.Activity] with id [nodeId] has been launched by invoking 432 * the [nodeName] contract from inside the [sourceNodeId] node with [argument] while expecting a 433 * result. Concluded by matching [ActivityNodeResultReceived] event. 434 * 435 * Spawned at [sourceNodeId]. 436 * 437 * @property nodeId target node id. 438 * @property nodeName target node name. 439 * @property nodeComponent target node component. 440 * @property sourceNodeId source node id. 441 * @property argument the argument supplied for launching target node with. 442 */ 443 data class ActivityNodeExecutedForResult( 444 override val nodeName: String, 445 override val nodeComponent: String, 446 override val sourceNodeId: Long, 447 override val nodeId: Long, 448 override val argument: Any? = null, 449 override val timestamp: Instant = Instant.now(), 450 ) : OnboardingActivityEvent, WithSource, WithArgument { 451 constructor( 452 sourceNodeId: Long, 453 nodeId: Long, 454 nodeClass: Class<*>, 455 argument: Any? = null, 456 timestamp: Instant = Instant.now(), 457 ) : this( 458 sourceNodeId = sourceNodeId, 459 nodeId = nodeId, 460 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 461 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 462 argument = argument, 463 timestamp = timestamp, 464 ) 465 466 override fun serialize(): OnboardingProtos.LogProto { 467 return OnboardingProtos.LogProto.newBuilder() 468 .setActivityNodeExecutedForResult( 469 OnboardingProtos.ActivityNodeExecutedForResultProto.newBuilder() 470 .setSourceNodeId(sourceNodeId) 471 .setNodeId(nodeId) 472 .setNodeName(nodeName) 473 .setNodeComponent(nodeComponent) 474 // .setArgument(argument) 475 .setTimestamp(timestamp.toEpochMilli()) 476 .build() 477 ) 478 .build() 479 } 480 481 companion object { 482 fun fromProto( 483 proto: OnboardingProtos.ActivityNodeExecutedForResultProto, 484 timestamp: Instant?, 485 ) = 486 ActivityNodeExecutedForResult( 487 sourceNodeId = proto.sourceNodeId, 488 nodeId = proto.nodeId, 489 nodeName = proto.nodeName, 490 nodeComponent = proto.nodeComponent, 491 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 492 ) 493 } 494 } 495 496 /** 497 * At [timestamp], the [result] of the [android.app.Activity] node with id [nodeId] was received. 498 * 499 * Note that this does not specify which node received the result. The event must be matched up 500 * with a previous [ActivityNodeExecutedForResult] event. 501 * 502 * Spawned at source node. 503 * 504 * @property nodeName name of the target node. 505 * @property nodeComponent name of the target node. 506 * @property nodeId id of the target node. 507 * @property result a result produced by the target node. 508 */ 509 data class ActivityNodeResultReceived( 510 override val nodeName: String, 511 override val nodeComponent: String, 512 override val nodeId: Long, 513 override val result: Any?, 514 override val timestamp: Instant = Instant.now(), 515 ) : OnboardingActivityEvent, WithResult { 516 constructor( 517 nodeId: Long, 518 nodeClass: Class<*>, 519 result: Any?, 520 timestamp: Instant = Instant.now(), 521 ) : this( 522 nodeId = nodeId, 523 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 524 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 525 result = result, 526 timestamp = timestamp, 527 ) 528 serializenull529 override fun serialize(): OnboardingProtos.LogProto { 530 return OnboardingProtos.LogProto.newBuilder() 531 .setActivityNodeResultReceived( 532 OnboardingProtos.ActivityNodeResultReceivedProto.newBuilder() 533 .setNodeId(nodeId) 534 .setNodeName(nodeName) 535 .setNodeComponent(nodeComponent) 536 // setResult(result) 537 .setTimestamp(timestamp.toEpochMilli()) 538 .build() 539 ) 540 .build() 541 } 542 543 companion object { fromProtonull544 fun fromProto(proto: OnboardingProtos.ActivityNodeResultReceivedProto, timestamp: Instant?) = 545 ActivityNodeResultReceived( 546 nodeId = proto.nodeId, 547 nodeName = proto.nodeName, 548 nodeComponent = proto.nodeComponent, 549 result = null, 550 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 551 ) 552 } 553 } 554 555 /** 556 * At [timestamp], the activity node with id [nodeId] called finish. 557 * 558 * Spawned at [nodeId]. 559 */ 560 data class ActivityNodeFinished( 561 override val nodeName: String, 562 override val nodeComponent: String, 563 override val nodeId: Long, 564 override val timestamp: Instant = Instant.now(), 565 ) : OnboardingActivityEvent { 566 constructor( 567 nodeId: Long, 568 nodeClass: Class<*>, 569 timestamp: Instant = Instant.now(), 570 ) : this( 571 nodeId = nodeId, 572 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 573 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 574 timestamp = timestamp, 575 ) 576 577 override fun serialize(): OnboardingProtos.LogProto { 578 return OnboardingProtos.LogProto.newBuilder() 579 .setActivityNodeFinished( 580 OnboardingProtos.ActivityNodeFinishedProto.newBuilder() 581 .setNodeId(nodeId) 582 .setNodeName(nodeName) 583 .setNodeComponent(nodeComponent) 584 .setTimestamp(timestamp.toEpochMilli()) 585 .build() 586 ) 587 .build() 588 } 589 590 companion object { 591 fun fromProto(proto: OnboardingProtos.ActivityNodeFinishedProto, timestamp: Instant?) = 592 ActivityNodeFinished( 593 nodeId = proto.nodeId, 594 nodeName = proto.nodeName, 595 nodeComponent = proto.nodeComponent, 596 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 597 ) 598 } 599 } 600 601 /** 602 * At [timestamp], the activity node with id [nodeId] resumes after it previously launched node 603 * with id [sourceNodeId]. 604 * 605 * Spawned at [nodeId]. 606 * 607 * @property sourceNodeId the id of the node that this node previously launched and now resumed 608 * from. 609 * @property nodeId the id of the node spawning this event. 610 * @property nodeName the name of the node spawning this event. 611 * @property nodeComponent the component of the node spawning this event. 612 */ 613 data class ActivityNodeResumedAfterLaunch( 614 override val nodeName: String, 615 override val nodeComponent: String, 616 override val sourceNodeId: Long, 617 override val nodeId: Long, 618 override val timestamp: Instant = Instant.now(), 619 ) : OnboardingActivityEvent, WithSource { 620 constructor( 621 sourceNodeId: Long, 622 nodeId: Long, 623 nodeClass: Class<*>, 624 timestamp: Instant = Instant.now(), 625 ) : this( 626 sourceNodeId = sourceNodeId, 627 nodeId = nodeId, 628 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 629 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 630 timestamp = timestamp, 631 ) 632 serializenull633 override fun serialize(): OnboardingProtos.LogProto { 634 return OnboardingProtos.LogProto.newBuilder() 635 .setActivityNodeResumedAfterLaunch( 636 OnboardingProtos.ActivityNodeResumedAfterLaunchProto.newBuilder() 637 .setSourceNodeId(sourceNodeId) 638 .setNodeId(nodeId) 639 .setNodeName(nodeName) 640 .setNodeComponent(nodeComponent) 641 .setTimestamp(timestamp.toEpochMilli()) 642 .build() 643 ) 644 .build() 645 } 646 647 companion object { fromProtonull648 fun fromProto( 649 proto: OnboardingProtos.ActivityNodeResumedAfterLaunchProto, 650 timestamp: Instant?, 651 ) = 652 ActivityNodeResumedAfterLaunch( 653 sourceNodeId = proto.sourceNodeId, 654 nodeId = proto.nodeId, 655 nodeName = proto.nodeName, 656 nodeComponent = proto.nodeComponent, 657 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 658 ) 659 } 660 } 661 662 /** 663 * At [timestamp], the activity node with id [nodeId] called finish. 664 * 665 * Spawned at [nodeId]. 666 */ 667 data class ActivityNodeResumed( 668 override val nodeName: String, 669 override val nodeComponent: String, 670 override val nodeId: Long, 671 override val timestamp: Instant = Instant.now(), 672 ) : OnboardingActivityEvent { 673 constructor( 674 nodeId: Long, 675 nodeClass: Class<*>, 676 timestamp: Instant = Instant.now(), 677 ) : this( 678 nodeId = nodeId, 679 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 680 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 681 timestamp = timestamp, 682 ) 683 684 override fun serialize(): OnboardingProtos.LogProto { 685 return OnboardingProtos.LogProto.newBuilder() 686 .setActivityNodeResumed( 687 OnboardingProtos.ActivityNodeResumedProto.newBuilder() 688 .setNodeId(nodeId) 689 .setNodeName(nodeName) 690 .setNodeComponent(nodeComponent) 691 .setTimestamp(timestamp.toEpochMilli()) 692 .build() 693 ) 694 .build() 695 } 696 697 companion object { 698 fun fromProto(proto: OnboardingProtos.ActivityNodeResumedProto, timestamp: Instant?) = 699 ActivityNodeResumed( 700 nodeId = proto.nodeId, 701 nodeName = proto.nodeName, 702 nodeComponent = proto.nodeComponent, 703 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 704 ) 705 } 706 } 707 708 /** An [OnboardingActivityEvent] spawned only from synchronous executions of contracts. */ 709 sealed interface OnboardingSynchronousActivityEvent : OnboardingActivityEvent 710 711 /** 712 * At [timestamp], the node with id [sourceNodeId] began synchronous execution of the node with id 713 * [nodeId]. Concluded by matching [ActivityNodeExecutedSynchronously] event. Note that 714 * [OnboardingEvent.ActivityNodeExecutedForResult] will always be spawned immediately after this 715 * event in the same flow. 716 * 717 * Spawned at [sourceNodeId]. 718 * 719 * @property nodeId target node id. 720 * @property nodeName target node name. 721 * @property nodeComponent target node component. 722 * @property sourceNodeId source node id. 723 * @property argument the argument supplied for launching target node with. 724 */ 725 data class ActivityNodeStartExecuteSynchronously( 726 override val nodeName: String, 727 override val nodeComponent: String, 728 override val sourceNodeId: Long, 729 override val nodeId: Long, 730 override val argument: Any?, 731 override val timestamp: Instant = Instant.now(), 732 ) : OnboardingSynchronousActivityEvent, WithSource, WithArgument { 733 constructor( 734 sourceNodeId: Long, 735 nodeId: Long, 736 nodeClass: Class<*>, 737 argument: Any? = null, 738 timestamp: Instant = Instant.now(), 739 ) : this( 740 sourceNodeId = sourceNodeId, 741 nodeId = nodeId, 742 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 743 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 744 argument = argument, 745 timestamp = timestamp, 746 ) 747 serializenull748 override fun serialize(): OnboardingProtos.LogProto { 749 return OnboardingProtos.LogProto.newBuilder() 750 .setActivityNodeStartExecuteSynchronously( 751 OnboardingProtos.ActivityNodeStartExecuteSynchronouslyProto.newBuilder() 752 .setSourceNodeId(sourceNodeId) 753 .setNodeId(nodeId) 754 .setNodeName(nodeName) 755 .setNodeComponent(nodeComponent) 756 // setArgument(argument) 757 .setTimestamp(timestamp.toEpochMilli()) 758 .build() 759 ) 760 .build() 761 } 762 763 companion object { fromProtonull764 fun fromProto( 765 proto: OnboardingProtos.ActivityNodeStartExecuteSynchronouslyProto, 766 timestamp: Instant?, 767 ) = 768 ActivityNodeStartExecuteSynchronously( 769 sourceNodeId = proto.sourceNodeId, 770 nodeId = proto.nodeId, 771 nodeName = proto.nodeName, 772 nodeComponent = proto.nodeComponent, 773 argument = null, 774 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 775 ) 776 } 777 } 778 779 /** 780 * At [timestamp], the synchronously executing node with id [nodeId] produced a [result]. 781 * 782 * Note that this does not specify which node received the result. The event must be matched up 783 * with a previous [ActivityNodeStartExecuteSynchronously] event. 784 * 785 * Spawned at source node. 786 * 787 * @property nodeName name of the target node. 788 * @property nodeComponent name of the target node. 789 * @property nodeId id of the target node. 790 */ 791 data class ActivityNodeExecutedSynchronously( 792 override val nodeName: String, 793 override val nodeComponent: String, 794 override val nodeId: Long, 795 override val result: Any?, 796 override val timestamp: Instant = Instant.now(), 797 ) : OnboardingSynchronousActivityEvent, WithResult { 798 constructor( 799 nodeId: Long, 800 nodeClass: Class<*>, 801 result: Any?, 802 timestamp: Instant = Instant.now(), 803 ) : this( 804 nodeId = nodeId, 805 nodeName = OnboardingNode.extractNodeNameFromClass(nodeClass), 806 nodeComponent = OnboardingNode.extractComponentNameFromClass(nodeClass), 807 result = result, 808 timestamp = timestamp, 809 ) 810 811 override fun serialize(): OnboardingProtos.LogProto { 812 return OnboardingProtos.LogProto.newBuilder() 813 .setActivityNodeExecutedSynchronously( 814 OnboardingProtos.ActivityNodeExecutedSynchronouslyProto.newBuilder() 815 .setNodeId(nodeId) 816 .setNodeName(nodeName) 817 .setNodeComponent(nodeComponent) 818 // setResult(result) 819 .setTimestamp(timestamp.toEpochMilli()) 820 .build() 821 ) 822 .build() 823 } 824 825 companion object { 826 fun fromProto( 827 proto: OnboardingProtos.ActivityNodeExecutedSynchronouslyProto, 828 timestamp: Instant?, 829 ) = 830 ActivityNodeExecutedSynchronously( 831 nodeId = proto.nodeId, 832 nodeName = proto.nodeName, 833 nodeComponent = proto.nodeComponent, 834 result = null, 835 timestamp = timestamp ?: Instant.ofEpochMilli(proto.timestamp), 836 ) 837 } 838 } 839 840 // LINT.ThenChange(//depot/google3/logs/proto/android_onboarding/node_interaction_metadata.proto) 841 842 /** 843 * Wrapper around the same information as [android.content.Intent] but can be used without 844 * dependency on Android. 845 */ 846 data class IntentData(val action: String?, val extras: Map<String, Any?>) 847 848 companion object { deserializenull849 fun deserialize(str: String, timestamp: Instant? = null): OnboardingEvent { 850 val proto = OnboardingProtos.LogProto.parseFrom(BaseEncoding.base64().decode(str)) 851 852 return when { 853 proto.hasActivityNodeExecutedDirectly() -> 854 ActivityNodeExecutedDirectly.fromProto(proto.activityNodeExecutedDirectly, timestamp) 855 proto.hasActivityNodeExecutedForResult() -> 856 ActivityNodeExecutedForResult.fromProto(proto.activityNodeExecutedForResult, timestamp) 857 proto.hasActivityNodeValidating() -> 858 ActivityNodeValidating.fromProto(proto.activityNodeValidating, timestamp) 859 proto.hasActivityNodeFailedValidation() -> 860 ActivityNodeFailedValidation.fromProto(proto.activityNodeFailedValidation, timestamp) 861 proto.hasActivityNodeExtractArgument() -> 862 ActivityNodeExtractArgument.fromProto(proto.activityNodeExtractArgument, timestamp) 863 proto.hasActivityNodeArgumentExtracted() -> 864 ActivityNodeArgumentExtracted.fromProto(proto.activityNodeArgumentExtracted, timestamp) 865 proto.hasActivityNodeSetResult() -> 866 ActivityNodeSetResult.fromProto(proto.activityNodeSetResult, timestamp) 867 proto.hasActivityNodeFail() -> ActivityNodeFail.fromProto(proto.activityNodeFail, timestamp) 868 proto.hasActivityNodeResultReceived() -> 869 ActivityNodeResultReceived.fromProto(proto.activityNodeResultReceived, timestamp) 870 proto.hasActivityNodeStartExecuteSynchronously() -> 871 ActivityNodeStartExecuteSynchronously.fromProto( 872 proto.activityNodeStartExecuteSynchronously, 873 timestamp, 874 ) 875 proto.hasActivityNodeExecutedSynchronously() -> 876 ActivityNodeExecutedSynchronously.fromProto( 877 proto.activityNodeExecutedSynchronously, 878 timestamp, 879 ) 880 proto.hasActivityNodeFinished() -> 881 ActivityNodeFinished.fromProto(proto.activityNodeFinished, timestamp) 882 proto.hasActivityNodeResumedAfterLaunch() -> 883 ActivityNodeResumedAfterLaunch.fromProto(proto.activityNodeResumedAfterLaunch, timestamp) 884 proto.hasActivityNodeResumed() -> 885 ActivityNodeResumed.fromProto(proto.activityNodeResumed, timestamp) 886 else -> throw IllegalStateException("Could not parse $proto") 887 } 888 } 889 } 890 } 891